Goose  Check-in [0345b9f807]

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

Overview
Comment:Some more renaming.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 0345b9f80713cb5eef151494f9f3b03f33aefbc61b44b256e60230d7b79c6905
User & Date: achavasse 2021-01-02 18:00:11.039
Context
2021-01-02
18:24
Yet one more reference/address refactor: each calculation step (getting temp addr, getting var addr, selecting a member) is now a separate cir instruction. We need this level of generalization to be able to obtain addresses from anywhere, including variables and function parameters. check-in: 26c691ecb9 user: achavasse tags: trunk
18:00
Some more renaming. check-in: 0345b9f807 user: achavasse tags: trunk
2020-12-27
14:40
Renamed "ir" to "eir" (expression intermediate representation) and "llr" to "cir" (code intermediate representation) for clarity. check-in: 7d2def7b75 user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/api/codegen/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
    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( *ValueFromIRExpr( 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( *ValueFromIRExpr( f.type() ) ) )
                    return false;

                sema::Context c( pEnv.lock(), RootIdentity() );

                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );








|


















|







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
    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 );

Changes to bs/builtins/api/codegen/module.cpp.
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    }
}

namespace goose::eir
{
    const Term& Bridge< ptr< codegen::Module > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( cg_module ) ) ) );
        return type;
    }

    Value Bridge< ptr< codegen::Module > >::ToValue( const ptr< codegen::Module >& os )
    {
        return Value( Type(), TERM( static_pointer_cast< void >( os ) ) );
    }







|







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
    }
}

namespace goose::eir
{
    const Term& Bridge< ptr< codegen::Module > >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( cg_module ) ) ) );
        return type;
    }

    Value Bridge< ptr< codegen::Module > >::ToValue( const ptr< codegen::Module >& os )
    {
        return Value( Type(), TERM( static_pointer_cast< void >( os ) ) );
    }
Changes to bs/builtins/api/compiler.cpp.
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
                    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( _ ), ValueToIRExpr( v ) );
            } );

        RegisterBuiltinFunc< Intrinsic< uint32_t ( string ) > >( e, "#Include"_sid,
            [pEnv]( auto&& c, const Value& fnameval ) -> Value
            {
                auto filename = *FromValue< string >( fnameval );








|







128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
                    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 );

186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
                    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(), ValueToIRExpr( rt ) );
                auto ftype = BuildFuncType( localC, rt, params );

                auto funcIdentity = AppendToVectorTerm( builtins::RootIdentity(),
                    TERM( StringId( Env::NewUniqueId() ) ) );

                c.env()->addVisibilityRule( builtins::RootIdentity(), funcIdentity );








|







186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
                    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 );

                auto funcIdentity = AppendToVectorTerm( builtins::RootIdentity(),
                    TERM( StringId( Env::NewUniqueId() ) ) );

                c.env()->addVisibilityRule( builtins::RootIdentity(), funcIdentity );

Changes to bs/builtins/api/extensibility/codebuilder.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "builtins/builtins.h"
#include "eir/eir.h"

namespace goose::eir
{
    const Term& Bridge< ptr< sema::CodeBuilder > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_codebuilder ) ) ) );
        return type;
    }

    Value Bridge< ptr< sema::CodeBuilder > >::ToValue( const ptr< sema::CodeBuilder >& cb )
    {
        return Value( Type(), TERM( static_pointer_cast< void >( cb ) ) );
    }







|







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

namespace goose::eir
{
    const Term& Bridge< ptr< sema::CodeBuilder > >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_codebuilder ) ) ) );
        return type;
    }

    Value Bridge< ptr< sema::CodeBuilder > >::ToValue( const ptr< sema::CodeBuilder >& cb )
    {
        return Value( Type(), TERM( static_pointer_cast< void >( cb ) ) );
    }
Changes to bs/builtins/api/extensibility/termwrapper.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "builtins/builtins.h"
#include "eir/eir.h"

using namespace goose::builtins;

namespace goose::eir
{
    const Term& Bridge< TermWrapper >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_termwrapper ) ) ) );
        return type;
    }

    Value Bridge< TermWrapper >::ToValue( const TermWrapper& tw )
    {
        return Value( Type(), Quote( tw.get() ) );
    }









|







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

using namespace goose::builtins;

namespace goose::eir
{
    const Term& Bridge< TermWrapper >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_termwrapper ) ) ) );
        return type;
    }

    Value Bridge< TermWrapper >::ToValue( const TermWrapper& tw )
    {
        return Value( Type(), Quote( tw.get() ) );
    }
Changes to bs/builtins/api/extensibility/valuewrapper.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
#include "builtins/builtins.h"
#include "eir/eir.h"

using namespace goose::builtins;

namespace goose::eir
{
    const Term& Bridge< ValueWrapper >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_valuewrapper ) ) ) );
        return type;
    }

    Value Bridge< ValueWrapper >::ToValue( const ValueWrapper& vw )
    {
        return Value( Type(), Quote( ValueToIRExpr( vw.get() ) ) );
    }

    optional< Value > Bridge< ValueWrapper >::FromValue( const Value& v )
    {
        if( v.type() != Type() )
            return nullopt;

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

        return ValueFromIRExpr( *uq );
    }
}









|





|











|


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
#include "builtins/builtins.h"
#include "eir/eir.h"

using namespace goose::builtins;

namespace goose::eir
{
    const Term& Bridge< ValueWrapper >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( ext_valuewrapper ) ) ) );
        return type;
    }

    Value Bridge< ValueWrapper >::ToValue( const ValueWrapper& vw )
    {
        return Value( Type(), Quote( ValueToEIR( vw.get() ) ) );
    }

    optional< Value > Bridge< ValueWrapper >::FromValue( const Value& v )
    {
        if( v.type() != Type() )
            return nullopt;

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

        return ValueFromEIR( *uq );
    }
}
Changes to bs/builtins/helpers.cpp.
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

        np.flushValue();
        return bb;
    }

    variant< Value, ValUnifyError > ConvertValueToType( const Context& c, const Value& val, const Term& type )
    {
        auto valTerm = ValueToIRExpr( val );
        auto paramPat = ParamPat( type );

        auto us = FindBestTyping( paramPat, valTerm, c );

        if( holds_alternative< NoUnification >( us ) )
            return ValUnifyError::NoSolution;

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

        auto&& [s,tcc] = get< TCSol >( us );
        auto finalVal = ValueFromIRExpr( s );
        assert( finalVal );

        return *finalVal;
    }

    pvec ParseExpressionList( Parser& p, uint32_t precedence, const pvec& pVec )
    {
        while( p.parseExpression( precedence ) )
        {
            auto val = p.popValue();
            if( !val || val->isPoison() )
                return nullptr;

            pVec->append( ValueToIRExpr( *val ) );
        }

        return pVec;
    }
}







|











|













|





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

        np.flushValue();
        return bb;
    }

    variant< Value, ValUnifyError > ConvertValueToType( const Context& c, const Value& val, const Term& type )
    {
        auto valTerm = ValueToEIR( val );
        auto paramPat = ParamPat( type );

        auto us = FindBestTyping( paramPat, valTerm, c );

        if( holds_alternative< NoUnification >( us ) )
            return ValUnifyError::NoSolution;

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

        auto&& [s,tcc] = get< TCSol >( us );
        auto finalVal = ValueFromEIR( s );
        assert( finalVal );

        return *finalVal;
    }

    pvec ParseExpressionList( Parser& p, uint32_t precedence, const pvec& pVec )
    {
        while( p.parseExpression( precedence ) )
        {
            auto val = p.popValue();
            if( !val || val->isPoison() )
                return nullptr;

            pVec->append( ValueToEIR( *val ) );
        }

        return pVec;
    }
}
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 = *ValueFromIRExpr( 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 = *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,
Changes to bs/builtins/operators/assignment.cpp.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

        // 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
        {
            auto ref = *FromValue< Reference >( lhs );

            if( !ParseTypePredicates( c, c.identity(), *ValueFromIRExpr( ref.type().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

        // 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
        {
            auto ref = *FromValue< Reference >( lhs );

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

            const auto& cb = c.codeBuilder();
            if( !cb )
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( 0, "assignments are not allowed here." );
                return PoisonValue();
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
                        // We go at very high level to construct the temporary variables by resolving an invocation
                        // of the assignment of the rhs value to a TNamedDecl with an empty name.
                        // The reason we need to work at such high level is so that the initializer value gets
                        // resolved exactly like if it was a regular assignment. In particular, if the value in question
                        // is a locvar, we want it to go through the type checking process to be replaced with its content.
                        // This is the simplest and most robust way to achieve this, which should honor every relevant
                        // extension point.
                        auto anonVarDecl = ToValue( TNamedDecl( ValueToIRExpr( ToValue( TVar( "_"_sid ) ) ), ""_sid ) );

                        auto tmpVar = InvokeOverloadSet( c,
                            assOp, MakeTuple( anonVarDecl, srcVal ) );

                        if( tmpVar.isPoison() )
                        {
                            success = false;







|







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
                        // We go at very high level to construct the temporary variables by resolving an invocation
                        // of the assignment of the rhs value to a TNamedDecl with an empty name.
                        // The reason we need to work at such high level is so that the initializer value gets
                        // resolved exactly like if it was a regular assignment. In particular, if the value in question
                        // is a locvar, we want it to go through the type checking process to be replaced with its content.
                        // This is the simplest and most robust way to achieve this, which should honor every relevant
                        // extension point.
                        auto anonVarDecl = ToValue( TNamedDecl( ValueToEIR( ToValue( TVar( "_"_sid ) ) ), ""_sid ) );

                        auto tmpVar = InvokeOverloadSet( c,
                            assOp, MakeTuple( anonVarDecl, srcVal ) );

                        if( tmpVar.isPoison() )
                        {
                            success = false;
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 *ValueFromIRExpr( 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 *ValueFromEIR( result );

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

            default:
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
            DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( nameTerm->second,
                "expected an unbound identifier after '$'." );
            return false;
        }

        auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );

        auto typeOrTExpr = ValueToIRExpr( *p.popValue() );
        auto tdecl = builtins::BuildTDecl( c, move( typeOrTExpr ), *name );
        assert( tdecl );

        p.pushValue( ToValue( move( *tdecl ) ).setLocationId( loc ) );
        return true;
    }
}







|







120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
            DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( nameTerm->second,
                "expected an unbound identifier after '$'." );
            return false;
        }

        auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );

        auto typeOrTExpr = ValueToEIR( *p.popValue() );
        auto tdecl = builtins::BuildTDecl( c, move( typeOrTExpr ), *name );
        assert( tdecl );

        p.pushValue( ToValue( move( *tdecl ) ).setLocationId( loc ) );
        return true;
    }
}
Changes to bs/builtins/operators/dot.cpp.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
                    if( !rhs.isConstant() )
                    {
                        DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
                            "the right operand for the dot operator needs to be a constant." );
                        return PoisonValue();
                    }

                    auto tupType = *ValueFromIRExpr( lhs.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();







|







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

                    auto tupType = *ValueFromEIR( lhs.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();
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
                    {
                        DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
                            "the right operand for the dot operator needs to be a constant." );
                        return PoisonValue();
                    }

                    auto lv = *FromValue< LocalVar >( lhs );
                    auto tupType = *ValueFromIRExpr( lv.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();







|







62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
                    {
                        DiagnosticsManager::GetInstance().emitErrorMessage( rhs.locationId(),
                            "the right operand for the dot operator needs to be a constant." );
                        return PoisonValue();
                    }

                    auto lv = *FromValue< LocalVar >( lhs );
                    auto tupType = *ValueFromEIR( lv.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/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 = *ValueFromIRExpr( 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 = *ValueFromEIR( 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( *ValueFromIRExpr( 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( *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 >(),
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( *ValueFromIRExpr( 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( *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 >(),
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 >( *ValueFromIRExpr( 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 >( *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 >( *ValueFromIRExpr( 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." );

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 >( *ValueFromIRExpr( 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." );

Changes to bs/builtins/statements/break.cpp.
37
38
39
40
41
42
43
44
45
46
47

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

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







|



37
38
39
40
41
42
43
44
45
46
47

            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 );
    }
}
Changes to bs/builtins/statements/continue.cpp.
37
38
39
40
41
42
43
44
45
46
47

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

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







|



37
38
39
40
41
42
43
44
45
46
47

            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 );
    }
}
Changes to bs/builtins/statements/hif.cpp.
127
128
129
130
131
132
133
134
135
136
137
            }

            return true;
        };

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







|



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 );
    }
}
Changes to bs/builtins/statements/if.cpp.
135
136
137
138
139
140
141
142
143
144
145
            // instructions.
            cfg->setCurrentBB( pSuccBB );
            return true;
        };

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







|



135
136
137
138
139
140
141
142
143
144
145
            // 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 );
    }
}
Changes to bs/builtins/statements/return.cpp.
81
82
83
84
85
86
87
88
89
90
91

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

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







|



81
82
83
84
85
86
87
88
89
90
91

            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 );
    }
}
Changes to bs/builtins/statements/using.cpp.
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
            get< pvec >( localIdentity )->terms().back() = nameTerm->first;
            context.env()->addVisibilityRule( context.identity(), localIdentity );

            auto eqTerm = p.resolver()->consumeUnresolved();
            if( !eqTerm )
            {
                dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "expected '='.", 0 );
                context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToIRExpr( PoisonValue() ) );
                return true;
            }

            const auto* eq = get_if< StringId >( &eqTerm->first );
            if( !eq || *eq != "="_sid )
            {
                dm.emitSyntaxErrorMessage( eqTerm->second, "expected '='.", 0 );
                context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToIRExpr( PoisonValue() ) );
                return true;
            }

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::UsingStmt ) )
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                    "expected an expression.", 0 );
                context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToIRExpr( PoisonValue() ) );
                return true;
            }

            if( !np.peekLastValue() )
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                    "expected an expression.", 0 );
                context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToIRExpr( PoisonValue() ) );
                return true;
            }

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

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







|







|








|







|



|





|



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
            get< pvec >( localIdentity )->terms().back() = nameTerm->first;
            context.env()->addVisibilityRule( context.identity(), localIdentity );

            auto eqTerm = p.resolver()->consumeUnresolved();
            if( !eqTerm )
            {
                dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "expected '='.", 0 );
                context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( PoisonValue() ) );
                return true;
            }

            const auto* eq = get_if< StringId >( &eqTerm->first );
            if( !eq || *eq != "="_sid )
            {
                dm.emitSyntaxErrorMessage( eqTerm->second, "expected '='.", 0 );
                context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( PoisonValue() ) );
                return true;
            }

            auto np = p.makeNestedParser();
            if( !np.parseExpression( precedence::UsingStmt ) )
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                    "expected an expression.", 0 );
                context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( PoisonValue() ) );
                return true;
            }

            if( !np.peekLastValue() )
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( locationId,
                    "expected an expression.", 0 );
                context.env()->storeValue( localIdentity, ANYTERM( _ ), ValueToEIR( PoisonValue() ) );
                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 );
    }
}
Changes to bs/builtins/statements/while.cpp.
140
141
142
143
144
145
146
147
148
149
150

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

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







|



140
141
142
143
144
145
146
147
148
149
150

            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 );
    }
}
Changes to bs/builtins/types/basic.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
48
49
50
51
52
53
54
        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( _ ), ValueToIRExpr( ToValue( true ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( false ) ), ANYTERM( _ ), ValueToIRExpr( ToValue( false ) ) );

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

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

namespace goose::eir
{
    // void
    const Term& Bridge< void >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( void ) ) );
        return type;
    }

    // bool
    const Term& Bridge< bool >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), MkStdType( TSID( bool ) ) ) );
        return type;
    }

    Value Bridge< bool >::ToValue( bool x )
    {
        return Value( Type(), TERM( x ? 1U : 0U ) );
    }







|
|


|
|














|






|







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
        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 );
        return pattern;
    }
}

namespace goose::eir
{
    // void
    const Term& Bridge< void >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), TSID( void ) ) );
        return type;
    }

    // bool
    const Term& Bridge< bool >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), MkStdType( TSID( bool ) ) ) );
        return type;
    }

    Value Bridge< bool >::ToValue( bool x )
    {
        return Value( Type(), TERM( x ? 1U : 0U ) );
    }
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

        return *pint;
    }

    // Integers
    const Term& Bridge< BigInt >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_integer ) ) ) );
        return type;
    }

    const BigInt* Bridge< BigInt >::FromValue( const Value& v )
    {
        if( v.type() != Type() )
            return nullptr;

        return get_if< BigInt >( &v.val() );
    }

    // char
    const Term& Bridge< char32_t >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_char ) ) ) );
        return type;
    }

    Value Bridge< char32_t >::ToValue( char32_t x )
    {
        return Value( Type(), TERM( x ) );
    }

    optional< char32_t > Bridge< char32_t >::FromValue( const Value& v )
    {
        if( v.type() != Type() )
            return nullopt;

        return get< uint32_t >( v.val() );
    }

    // strings
    const Term& Bridge< string >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_string ) ) ) );
        return type;
    }

    Value Bridge< string >::ToValue( const string& x )
    {
        return Value( Type(), TERM( x ) );
    }







|














|



















|







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

        return *pint;
    }

    // Integers
    const Term& Bridge< BigInt >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_integer ) ) ) );
        return type;
    }

    const BigInt* Bridge< BigInt >::FromValue( const Value& v )
    {
        if( v.type() != Type() )
            return nullptr;

        return get_if< BigInt >( &v.val() );
    }

    // char
    const Term& Bridge< char32_t >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_char ) ) ) );
        return type;
    }

    Value Bridge< char32_t >::ToValue( char32_t x )
    {
        return Value( Type(), TERM( x ) );
    }

    optional< char32_t > Bridge< char32_t >::FromValue( const Value& v )
    {
        if( v.type() != Type() )
            return nullopt;

        return get< uint32_t >( v.val() );
    }

    // strings
    const Term& Bridge< string >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), MkStdType( TSID( ct_type ), TSID( ct_string ) ) ) );
        return type;
    }

    Value Bridge< string >::ToValue( const string& x )
    {
        return Value( Type(), TERM( x ) );
    }
Changes to bs/builtins/types/constrainedfunc/constrainedfunc.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
#include "builtins/builtins.h"

using namespace goose::builtins;

bool goose::builtins::IsConstrainedFunc( const Value& tcc )
{
    return tcc.type() == GetValueType< ConstrainedFunc >();
}

namespace goose::eir
{
    const Term& Bridge< builtins::ConstrainedFunc >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( constrainedfunc ) ) ) );
        return type;
    }

    Value Bridge< builtins::ConstrainedFunc >::ToValue( const builtins::ConstrainedFunc& cf )
    {
        return Value( Type(), VEC(
            Quote( cf.constraintPat() ),
            TERM( static_pointer_cast< void >( cf.invRule() ) ),
            ValueToIRExpr( cf.func() ) ) );
    }

    optional< builtins::ConstrainedFunc > Bridge< builtins::ConstrainedFunc >::FromValue( const Value& v )
    {
        if( !IsConstrainedFunc( v ) )
            return nullopt;














|








|







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
#include "builtins/builtins.h"

using namespace goose::builtins;

bool goose::builtins::IsConstrainedFunc( const Value& tcc )
{
    return tcc.type() == GetValueType< ConstrainedFunc >();
}

namespace goose::eir
{
    const Term& Bridge< builtins::ConstrainedFunc >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( constrainedfunc ) ) ) );
        return type;
    }

    Value Bridge< builtins::ConstrainedFunc >::ToValue( const builtins::ConstrainedFunc& cf )
    {
        return Value( Type(), VEC(
            Quote( cf.constraintPat() ),
            TERM( static_pointer_cast< void >( cf.invRule() ) ),
            ValueToEIR( cf.func() ) ) );
    }

    optional< builtins::ConstrainedFunc > Bridge< builtins::ConstrainedFunc >::FromValue( const Value& v )
    {
        if( !IsConstrainedFunc( v ) )
            return nullopt;

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 ),
            *ValueFromIRExpr( 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 ),
            *ValueFromEIR( func ) );
    }
}
Changes to bs/builtins/types/constrainedfunc/invoke.cpp.
32
33
34
35
36
37
38
39
40
41
42
43
44
                return PoisonValue();
            }
    };

    void SetupConstrainedFuncInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToIRExpr( Value(
                GetValueType< ConstrainedFunc >(),
                ANYTERM( _ ) ) ),
            make_shared< ConstrainedFuncInvocationRule >() );
    }
}







|





32
33
34
35
36
37
38
39
40
41
42
43
44
                return PoisonValue();
            }
    };

    void SetupConstrainedFuncInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToEIR( Value(
                GetValueType< ConstrainedFunc >(),
                ANYTERM( _ ) ) ),
            make_shared< ConstrainedFuncInvocationRule >() );
    }
}
Changes to bs/builtins/types/constrainedfunc/typecheck.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
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
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupConstrainedFuncTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ) ) ) );

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / constrainedfunc arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( move( funcTypePat ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                GetValueType< builtins::ConstrainedFunc >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

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

            auto localC = tcc;
            for( auto&& [s, tcc] : TypeCheck( callPat, cfunc->constraintPat(), localC ) )
            {
                if( Postprocess( s, tcc ) )
                {
                    auto func = ValueToIRExpr( cfunc->func() );
                    co_yield TypeCheck( lhs, func, tcc );
                    co_return;
                }
            }
        } );

        // tfunc type param / constrainedfunc arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern( HOLE( "_"_sid ), move( tFuncTypePat ), HOLE( "_"_sid ) ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                GetValueType< builtins::ConstrainedFunc >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

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

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

        // constrainedfunc param / any arg:
        // Just yield the constrained func.
        //
        // This is because when we monomorphize a function that takes
        // a polymorphic function type, we turn the later into a
        // compile time constant. So it isn't really a parameter
        // in the resulting monomorphic function, and we just want
        // to ignore whatever parameter is being passed there
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                GetValueType< builtins::ConstrainedFunc >(),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            co_yield { lhs, tcc };
        } );
    }
}









|


|







|


















|

|








|









|

|


















|


|








|
















|




|










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
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
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupConstrainedFuncTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ) ) ) );

        auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / constrainedfunc arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( move( funcTypePat ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< builtins::ConstrainedFunc >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    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 ) )
                {
                    auto func = ValueToEIR( cfunc->func() );
                    co_yield TypeCheck( lhs, func, tcc );
                    co_return;
                }
            }
        } );

        // tfunc type param / constrainedfunc arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern( HOLE( "_"_sid ), move( tFuncTypePat ), HOLE( "_"_sid ) ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< builtins::ConstrainedFunc >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    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 ) )
                {
                    auto func = ValueToEIR( cfunc->func() );
                    co_yield TypeCheck( lhs, func, tcc );
                    co_return;
                }
            }
        } );

        // constrainedfunc param / any arg:
        // Just yield the constrained func.
        //
        // This is because when we monomorphize a function that takes
        // a polymorphic function type, we turn the later into a
        // compile time constant. So it isn't really a parameter
        // in the resulting monomorphic function, and we just want
        // to ignore whatever parameter is being passed there
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< builtins::ConstrainedFunc >(),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            co_yield { lhs, tcc };
        } );
    }
}
Changes to bs/builtins/types/decl.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
#include "builtins/builtins.h"

using namespace goose::builtins;

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

        return !!result;
    }

    const Term& Decl::Pattern::GetPattern()
    {
        static auto pattern = ValueToIRExpr(
            Value( TypeType(), VEC( TSID( decl ), HOLE( "_"_sid ) ) ) );

        return pattern;
    }
}

namespace goose::eir
{
    Term Bridge< Decl >::Type( const Term& declType )
    {
        return ValueToIRExpr( Value( TypeType(), VEC( TSID( decl ), declType ) ) );
    }

    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 = ValueFromIRExpr( v.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
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
#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()
            )
        );

        return !!result;
    }

    const Term& Decl::Pattern::GetPattern()
    {
        static auto pattern = ValueToEIR(
            Value( TypeType(), VEC( TSID( decl ), HOLE( "_"_sid ) ) ) );

        return pattern;
    }
}

namespace goose::eir
{
    Term Bridge< Decl >::Type( const Term& declType )
    {
        return ValueToEIR( Value( TypeType(), VEC( TSID( decl ), declType ) ) );
    }

    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()
            )
        );

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 = ValueFromIRExpr( 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 = ValueFromEIR( 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 = ValueFromIRExpr( 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()   // varArg
            )
        );

        return !!decomp;
    }

    bool IsEagerBuiltinFunc( const Value& func )
    {
        auto funcType = ValueFromIRExpr( 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 = 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()   // varArg
            )
        );

        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
Changes to bs/builtins/types/func/bfunc.inl.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
        auto identity = AppendToVectorTerm( RootIdentity(), TERM( name ) );

        Term result;

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

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

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

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







|




|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
        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:
                throw logic_error( "panic: ambiguous match while registering builtin func "s + name.str() );
        }

        return RegisterBuiltinFunc< FT >( env, pOvlSet, forward< F >( func ) );
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
    {
        return VEC( BuildBuiltinFuncParamPat< T >::GetParamPattern()... );
    }

    template< typename R, typename... T >
    const Term& Bridge< R ( T... ) >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            builtins::is_eager_v< R > ? TSID( builtin_eager ) : TSID( builtin ),
            GetValueType< builtins::remove_eager_t< R > >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
            static_pointer_cast< void >( fvi ), TERM( 0U )
        ) ) );
        return type;
    }







|







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
    {
        return VEC( BuildBuiltinFuncParamPat< T >::GetParamPattern()... );
    }

    template< typename R, typename... T >
    const Term& Bridge< R ( T... ) >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
            builtins::is_eager_v< R > ? TSID( builtin_eager ) : TSID( builtin ),
            GetValueType< builtins::remove_eager_t< R > >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
            static_pointer_cast< void >( fvi ), TERM( 0U )
        ) ) );
        return type;
    }
Changes to bs/builtins/types/func/build.cpp.
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
                // Bind a stand-in value with the parameters name to be used inside of verification expressions.
                auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
                    TERM( decl.name() ) );

                Reference argRef( ReferenceType{ decl.type(), TSID( const ) }, cir::VarBaseAddr( varId++ ) );

                c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
                    ValueToIRExpr( BuildComputedValue( decl.type(),
                    cir::Load( ToValue( argRef ), decl.type() ) ) ) );
            }
            else if( param.isConstant() )
                tv->append( ValueToIRExpr( param ) );

            return true;
        } );

        // If the return type is non-void, expose @result under the verification identity as a computed value whose type
        // is the function's return type, and the value is a placeholder cir instruction. This will allow verification
        // expressions to refer to the current function's return value as a value of the correct type.
        auto rtTerm = ValueToIRExpr( returnType );
        if( rtTerm != GetValueType< void >() )
        {
            auto name = "@result"_sid;
            auto retValVerificationIdentity = AppendToVectorTerm( verificationIdentity, TERM( name ) );

            c.env()->storeValue( retValVerificationIdentity, ANYTERM( _ ),
                ValueToIRExpr( BuildComputedValue( rtTerm, cir::Placeholder( rtTerm, name ) ) ) );
        }

        auto pVerifInfos = make_shared< FuncVerificationInfos >( move( verificationIdentity ) );
        return FuncType( ValueToIRExpr( returnType ), tv, move( pVerifInfos ) );
    }

    Func BuildExternalFunc( FuncType funcType, const string& symbol, bool varArg )
    {
        funcType.setVarArg( varArg );
        return Func( funcType, symbol );
    }







|



|







|






|



|







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
                // Bind a stand-in value with the parameters name to be used inside of verification expressions.
                auto paramVerificationIdentity = AppendToVectorTerm( verificationIdentity,
                    TERM( decl.name() ) );

                Reference argRef( ReferenceType{ decl.type(), TSID( const ) }, cir::VarBaseAddr( varId++ ) );

                c.env()->storeValue( paramVerificationIdentity, ANYTERM( _ ),
                    ValueToEIR( BuildComputedValue( decl.type(),
                    cir::Load( ToValue( argRef ), decl.type() ) ) ) );
            }
            else if( param.isConstant() )
                tv->append( ValueToEIR( param ) );

            return true;
        } );

        // If the return type is non-void, expose @result under the verification identity as a computed value whose type
        // is the function's return type, and the value is a placeholder cir instruction. This will allow verification
        // expressions to refer to the current function's return value as a value of the correct type.
        auto rtTerm = ValueToEIR( returnType );
        if( rtTerm != GetValueType< void >() )
        {
            auto name = "@result"_sid;
            auto retValVerificationIdentity = AppendToVectorTerm( verificationIdentity, TERM( name ) );

            c.env()->storeValue( retValVerificationIdentity, ANYTERM( _ ),
                ValueToEIR( BuildComputedValue( rtTerm, cir::Placeholder( rtTerm, name ) ) ) );
        }

        auto pVerifInfos = make_shared< FuncVerificationInfos >( move( verificationIdentity ) );
        return FuncType( ValueToEIR( returnType ), tv, move( pVerifInfos ) );
    }

    Func BuildExternalFunc( FuncType funcType, const string& symbol, bool varArg )
    {
        funcType.setVarArg( varArg );
        return Func( funcType, symbol );
    }
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
        // TODO: instead of a normal import rule, we should use a custom visibility
        // rule that deals with variables from the parent context in a special way:
        // If the function body tries to access variables from the parent function,
        // we should invoke an overridable global function that can transform both the
        // variable object and the function type. This way, we can implement/customize
        // smart lexical captures from inside the language itself (and at a minimum, have
        // a default implementation that denies access to outside variables with an error)
        auto funcTypeTerm = ValueToIRExpr( ToValue( funcType ) );
        auto identity = VEC( funcIdentity, funcTypeTerm );

        assert( c.identity() != identity );
        c.env()->addVisibilityRule( c.identity(), identity );

        out_bodyContext = Context( c.env(), identity, funcType.returnType() );
        auto pFuncCIR = c.env()->createCIRFunc( identity );







|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
        // TODO: instead of a normal import rule, we should use a custom visibility
        // rule that deals with variables from the parent context in a special way:
        // If the function body tries to access variables from the parent function,
        // we should invoke an overridable global function that can transform both the
        // variable object and the function type. This way, we can implement/customize
        // smart lexical captures from inside the language itself (and at a minimum, have
        // a default implementation that denies access to outside variables with an error)
        auto funcTypeTerm = ValueToEIR( ToValue( funcType ) );
        auto identity = VEC( funcIdentity, funcTypeTerm );

        assert( c.identity() != identity );
        c.env()->addVisibilityRule( c.identity(), identity );

        out_bodyContext = Context( c.env(), identity, funcType.returnType() );
        auto pFuncCIR = c.env()->createCIRFunc( identity );
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
            assert( result );

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

            if( sort == TSID( constant ) )
                apv->append( param );
            else
                apv->append( ValueToIRExpr( ValuePattern( TSID( computed ), type, TERM( ptr< void >() ) ) ) );

            return true;
        } );

        return VEC( apv, ftype.returnType() );
    }
}







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
            assert( result );

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

            if( sort == TSID( constant ) )
                apv->append( param );
            else
                apv->append( ValueToEIR( ValuePattern( TSID( computed ), type, TERM( ptr< void >() ) ) ) );

            return true;
        } );

        return VEC( apv, ftype.returnType() );
    }
}
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, pFuncCIR->identity(), *ValueFromIRExpr( type ) ) )
                predsOk = false;

            return true;
        } );

        if( !predsOk )
            return false;

        // Perform lazy parsing on return type predicates
        if( !ParseTypePredicates( c, pFuncCIR->identity(), *ValueFromIRExpr( 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, pFuncCIR->identity(), *ValueFromEIR( type ) ) )
                predsOk = false;

            return true;
        } );

        if( !predsOk )
            return false;

        // Perform lazy parsing on return type predicates
        if( !ParseTypePredicates( c, pFuncCIR->identity(), *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() )
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
        localContext.setBuilder( cb );

        // Create the local variable bindings to access the function params
        // from inside the body, as well as the signature.
        uint32_t varId = 0;
        for( auto&& t : f.paramsDecl()->terms() )
        {
            auto param = *ValueFromIRExpr( t );

            if( !IsDecl( param ) )
                continue;

            auto decl = *FromValue< Decl >( param );

            auto paramIdentity = AppendToVectorTerm(
                pFuncCIR->identity(),// ANYTERM( _ ),
                TERM( decl.name() ) );

            // Create a locvar to hold the param.
            LocalVar lv( decl.name(), decl.type(), varId++ );
            auto locVar = ToValue( lv ).setLocationId( param.locationId() );

            c.env()->storeValue( paramIdentity, ANYTERM( _ ),
                ValueToIRExpr( locVar ) );

            cb->pushLiveValue( locVar, lv.index() );
        }

        auto tokProvider = lex::MakeVectorAdapter( *static_pointer_cast< vector< TermLoc > >( f.tokens() ) );
        auto r = make_shared< parse::Resolver >( tokProvider, localContext );
        Parser p( r );







|















|







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
        localContext.setBuilder( cb );

        // Create the local variable bindings to access the function params
        // from inside the body, as well as the signature.
        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(
                pFuncCIR->identity(),// ANYTERM( _ ),
                TERM( decl.name() ) );

            // Create a locvar to hold the param.
            LocalVar lv( decl.name(), decl.type(), varId++ );
            auto locVar = ToValue( lv ).setLocationId( param.locationId() );

            c.env()->storeValue( paramIdentity, ANYTERM( _ ),
                ValueToEIR( locVar ) );

            cb->pushLiveValue( locVar, lv.index() );
        }

        auto tokProvider = lex::MakeVectorAdapter( *static_pointer_cast< vector< TermLoc > >( f.tokens() ) );
        auto r = make_shared< parse::Resolver >( tokProvider, localContext );
        Parser p( r );
Changes to bs/builtins/types/func/func.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"
#include "verify/verify.h"
#include "builtins/helpers.h"

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

namespace goose::builtins
{
    const Term& FuncPattern::GetPattern()
    {
        static auto pattern = ValueToIRExpr(
            Value( TypeType(), VEC( TSID( func ), HOLE( "llvmType"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ) ) ) );

        return pattern;
    }














|







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

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

namespace goose::builtins
{
    const Term& FuncPattern::GetPattern()
    {
        static auto pattern = ValueToEIR(
            Value( TypeType(), VEC( TSID( func ), HOLE( "llvmType"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ),
            HOLE( "_"_sid ), HOLE( "_"_sid ) ) ) );

        return pattern;
    }

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
        );

        return !!result;
    }

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

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







|







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
        );

        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(),
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
        auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;

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

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

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







|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
        auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;

        return VEC( *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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
            return ParamListKind::Invalid;

        auto result = ParamListKind::Regular;

        const auto& vec = *get< pvec >( tup.val() );
        for( auto&& x : vec.terms() )
        {
            auto v = ValueFromIRExpr( 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;







|







110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
            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;
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        return FuncType( rtype, *Unquote( params ),
            static_pointer_cast< FuncVerificationInfos >( vinf ),
            static_cast< llvm::FunctionType* >( llvmtype ), varArg );
    }

    Term Bridge< Func >::Type( const builtins::Func& func )
    {
        return ValueToIRExpr( ::ToValue( func.type() ) );
    }

    Value Bridge< Func >::ToValue( const builtins::Func& func )
    {
        if( func.isExternal() )
            return Value( Type( func ), TERM( *func.symbol() ) );

        return Value( Type( func ), VEC(
            TERM( func.tokens() ), TERM( func.paramsDecl() ), TERM( func.cir() ) ) );
    }

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

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

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








|
















|







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
        return FuncType( rtype, *Unquote( params ),
            static_pointer_cast< FuncVerificationInfos >( vinf ),
            static_cast< llvm::FunctionType* >( llvmtype ), varArg );
    }

    Term Bridge< Func >::Type( const builtins::Func& func )
    {
        return ValueToEIR( ::ToValue( func.type() ) );
    }

    Value Bridge< Func >::ToValue( const builtins::Func& func )
    {
        if( func.isExternal() )
            return Value( Type( func ), TERM( *func.symbol() ) );

        return Value( Type( func ), VEC(
            TERM( func.tokens() ), TERM( func.paramsDecl() ), TERM( func.cir() ) ) );
    }

    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;

Changes to bs/builtins/types/func/invoke.cpp.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

                if( IsBuiltinFunc( newCallee ) )
                    return BuildComputedValue( unifiedRType, cir::Call( newCallee, unifiedArgs ) );

                if( IsIntrinsicFunc( newCallee ) )
                    return GetBuiltinIntrinsicFuncWrapper( newCallee )( c, unifiedArgs );

                auto ft = *FromValue< FuncType >( *ValueFromIRExpr( newCallee.type() ) );
                auto argList = BuildArgListForCall( ft, unifiedArgs );

                return BuildComputedValue( unifiedRType, cir::Call( newCallee, argList ) );
            }

            optional< Term > getSignature( const Value& callee ) const final
            {







|







58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

                if( IsBuiltinFunc( newCallee ) )
                    return BuildComputedValue( unifiedRType, cir::Call( newCallee, unifiedArgs ) );

                if( IsIntrinsicFunc( newCallee ) )
                    return GetBuiltinIntrinsicFuncWrapper( newCallee )( c, unifiedArgs );

                auto ft = *FromValue< FuncType >( *ValueFromEIR( newCallee.type() ) );
                auto argList = BuildArgListForCall( ft, unifiedArgs );

                return BuildComputedValue( unifiedRType, cir::Call( newCallee, argList ) );
            }

            optional< Term > getSignature( const Value& callee ) const final
            {
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
        static ptr< InvocationRule > pRule = make_shared< FunctionInvocationRule >();
        return pRule;
    }

    void SetupFunctionInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( ANYTERM( _ ),

                ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
                ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
                ANYTERM( _ ), ANYTERM( _ ) ) ) ),

                ANYTERM( _ ) ) ),
            GetFuncInvocationRule() );
    }
}







|

|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
        static ptr< InvocationRule > pRule = make_shared< FunctionInvocationRule >();
        return pRule;
    }

    void SetupFunctionInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToEIR( ValuePattern( ANYTERM( _ ),

                ValueToEIR( Value( TypeType(), VEC( TSID( func ),
                ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
                ANYTERM( _ ), ANYTERM( _ ) ) ) ),

                ANYTERM( _ ) ) ),
            GetFuncInvocationRule() );
    }
}
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, *ValueFromIRExpr( 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, *ValueFromEIR( 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
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
            {
                success = false;
                return false;
            }

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

                paramTypes.emplace_back( GetLLVMType( *type ) );

                vp->type() = ValueToIRExpr( *type );
                pv->append( ValueToIRExpr( *vp ) );
            }
            else
                pv->append( p );

            return true;
        } );

        if( !success )
            return nullopt;

        auto* pLLVMType = llvm::FunctionType::get( GetLLVMType( *rt ), paramTypes, ft.varArg() );
        if( !pLLVMType )
            return nullopt;

        return FuncType( ValueToIRExpr( *rt ), pv, nullptr, pLLVMType );
    }

    void SetupFunctionLowering( Env& e )
    {
        RegisterBuiltinFunc< Intrinsic< Value ( TypePatternParam< FuncPattern > ) > >( e, e.extLowerTypeForRuntime(),
            []( const Context& c, const Value& ft )
        {







|








|
|














|







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
            {
                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 ) );

                vp->type() = ValueToEIR( *type );
                pv->append( ValueToEIR( *vp ) );
            }
            else
                pv->append( p );

            return true;
        } );

        if( !success )
            return nullopt;

        auto* pLLVMType = llvm::FunctionType::get( GetLLVMType( *rt ), paramTypes, ft.varArg() );
        if( !pLLVMType )
            return nullopt;

        return FuncType( ValueToEIR( *rt ), pv, nullptr, pLLVMType );
    }

    void SetupFunctionLowering( Env& e )
    {
        RegisterBuiltinFunc< Intrinsic< Value ( TypePatternParam< FuncPattern > ) > >( e, e.extLowerTypeForRuntime(),
            []( const Context& c, const Value& ft )
        {
Changes to bs/builtins/types/func/typecheck.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
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
    void SetupFunctionTypeChecking( Env& e )
    {
        // Default param rule: we basically treat it like a regular value.
        // Things that need a more specific rule for params can override this with
        // more specific pattern.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                TSID( param ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto lhsVal = *ValuePatternFromIRExpr( lhs );
            lhsVal.sort() = HOLE( "_"_sid );
            co_yield Unify( ValueToIRExpr( lhsVal ), rhs, tcc );
        } );

        // Constant param rule
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

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

            // Unify the types
            for( auto&& [ut,tcc] : Unify( lhsVal.type(), rhsVal.type(), tcc ) )
            {
                // Unify the contents
                for( auto&& [uv,tcc] : Unify( lhsVal.val(), rhsVal.val(), tcc ) )
                {
                    ValuePattern result( move( ut ), move( uv ), rhsVal.locationId() );
                    co_yield { ValueToIRExpr( move( result ) ), tcc };
                }
            }
        } );

        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( RT ), ANYTERM( P ), ANYTERM( _ ), ANYTERM( VA ) ) ) );

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / func arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( funcTypePat ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                funcTypePat,
                ANYTERM( _ ) ) ),

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

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

            auto wrapped = WrapWithPostprocFunc( rhs, [rhsVal]( const Term& t, const TypeCheckingContext& tcc )
                -> optional< Term >
            {
                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );

                auto func = CompileFunc( tcc.context(), rhsVal );
                if( func.isPoison() )
                    return nullopt;

                return ValueToIRExpr( func );
            } );

            co_yield { move( wrapped ), tcc };
        } );

        // tfunc type param / func arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( move( tFuncTypePat ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                move( funcTypePat ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

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

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

            for( auto&& [s, tcc] : TypeCheck( sig, *callPat, tcc ) )
            {
                if( IsBuiltinFunc( rhsVal ) )
                {
                    co_yield { ValueToIRExpr( rhsVal ), tcc };
                    continue;
                }

                auto wrapped = WrapWithPostprocFunc( s, [rhsVal]( const Term& t, const TypeCheckingContext& tcc )
                    -> optional< Term >
                {
                    DiagnosticsContext dc( 0, true );
                    VerbosityContext vc( Verbosity::Normal, true );

                    auto func = CompileFunc( tcc.context(), rhsVal );
                    if( func.isPoison() )
                        return nullopt;

                    return ValueToIRExpr( func );
                } );

                co_yield { move( wrapped ), tcc };
            }
        } );
    }
}







|




|








|





|




|
















|




|


|







|






|

















|










|



















|


|






|













|







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
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
    void SetupFunctionTypeChecking( Env& e )
    {
        // Default param rule: we basically treat it like a regular value.
        // Things that need a more specific rule for params can override this with
        // more specific pattern.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                TSID( param ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto lhsVal = *ValuePatternFromIRExpr( lhs );
            lhsVal.sort() = HOLE( "_"_sid );
            co_yield Unify( ValueToEIR( lhsVal ), rhs, tcc );
        } );

        // Constant param rule
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                TSID( constant ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

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

            // Unify the types
            for( auto&& [ut,tcc] : Unify( lhsVal.type(), rhsVal.type(), tcc ) )
            {
                // Unify the contents
                for( auto&& [uv,tcc] : Unify( lhsVal.val(), rhsVal.val(), tcc ) )
                {
                    ValuePattern result( move( ut ), move( uv ), rhsVal.locationId() );
                    co_yield { ValueToEIR( move( result ) ), tcc };
                }
            }
        } );

        auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( RT ), ANYTERM( P ), ANYTERM( _ ), ANYTERM( VA ) ) ) );

        auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / func arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( funcTypePat ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                funcTypePat,
                ANYTERM( _ ) ) ),

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

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

            auto wrapped = WrapWithPostprocFunc( rhs, [rhsVal]( const Term& t, const TypeCheckingContext& tcc )
                -> optional< Term >
            {
                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );

                auto func = CompileFunc( tcc.context(), rhsVal );
                if( func.isPoison() )
                    return nullopt;

                return ValueToEIR( func );
            } );

            co_yield { move( wrapped ), tcc };
        } );

        // tfunc type param / func arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( move( tFuncTypePat ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                move( funcTypePat ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    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 sig = GetFuncSig( rhsVal );

            for( auto&& [s, tcc] : TypeCheck( sig, *callPat, tcc ) )
            {
                if( IsBuiltinFunc( rhsVal ) )
                {
                    co_yield { ValueToEIR( rhsVal ), tcc };
                    continue;
                }

                auto wrapped = WrapWithPostprocFunc( s, [rhsVal]( const Term& t, const TypeCheckingContext& tcc )
                    -> optional< Term >
                {
                    DiagnosticsContext dc( 0, true );
                    VerbosityContext vc( Verbosity::Normal, true );

                    auto func = CompileFunc( tcc.context(), rhsVal );
                    if( func.isPoison() )
                        return nullopt;

                    return ValueToEIR( func );
                } );

                co_yield { move( wrapped ), tcc };
            }
        } );
    }
}
Changes to bs/builtins/types/init.cpp.
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
        // 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 )
            {
                auto ref = *FromValue< Reference >( r );

                if( !ParseTypePredicates( c, c.identity(), *ValueFromIRExpr( ref.type().type() ) ) )
                    return PoisonValue();

                return BuildComputedValue( GetValueType< void >(),
                    Store( r, initVal ) );
            } );

        // Default initialization for ct_int vars
        RegisterBuiltinFunc< Intrinsic< Value ( CTIntMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                auto ref = *FromValue< Reference >( r );

                if( !ParseTypePredicates( c, c.identity(), *ValueFromIRExpr( ref.type().type() ) ) )
                    return PoisonValue();

                return BuildComputedValue( GetValueType< void >(),
                    Store( r, ToValue( BigInt() ) ) );
            } );

        // Default initialization for ct_string vars
        RegisterBuiltinFunc< Intrinsic< Value ( CTStringMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                auto ref = *FromValue< Reference >( r );

                if( !ParseTypePredicates( c, c.identity(), *ValueFromIRExpr( ref.type().type() ) ) )
                    return PoisonValue();

                return BuildComputedValue( GetValueType< void >(),
                    Store( r, ToValue( ""s ) ) );
            } );
    }
}







|












|












|







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
        // 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 )
            {
                auto ref = *FromValue< Reference >( r );

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

                return BuildComputedValue( GetValueType< void >(),
                    Store( r, initVal ) );
            } );

        // Default initialization for ct_int vars
        RegisterBuiltinFunc< Intrinsic< Value ( CTIntMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                auto ref = *FromValue< Reference >( r );

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

                return BuildComputedValue( GetValueType< void >(),
                    Store( r, ToValue( BigInt() ) ) );
            } );

        // Default initialization for ct_string vars
        RegisterBuiltinFunc< Intrinsic< Value ( CTStringMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                auto ref = *FromValue< Reference >( r );

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

                return BuildComputedValue( GetValueType< void >(),
                    Store( r, ToValue( ""s ) ) );
            } );
    }
}
Changes to bs/builtins/types/intrinsic/intrinsic.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "builtins/builtins.h"

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

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "intrinsic"_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 IsIntrinsicFunc( const Value& func )
    {
        auto funcType = ValueFromEIR( func.type() );
        assert( funcType );

        auto decomp = Decompose( funcType->val(),
            Vec(
                Lit( "func"_sid ),
                Lit( "intrinsic"_sid ),
                SubTerm(),  // return type
Changes to bs/builtins/types/intrinsic/intrinsic.inl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef GOOSE_BUILTINS_TYPES_INTRINSIC_INL
#define GOOSE_BUILTINS_TYPES_INTRINSIC_INL

namespace goose::eir
{
    template< typename R, typename... T >
    const Term& Bridge< builtins::Intrinsic< R ( T... ) > >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ), TSID( intrinsic ),
            GetValueType< Value >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
            static_pointer_cast< void >( fvi ), TERM( 0U )
        ) ) );
        return type;
    }









|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef GOOSE_BUILTINS_TYPES_INTRINSIC_INL
#define GOOSE_BUILTINS_TYPES_INTRINSIC_INL

namespace goose::eir
{
    template< typename R, typename... T >
    const Term& Bridge< builtins::Intrinsic< R ( T... ) > >::Type( const ptr< builtins::FuncVerificationInfos >& fvi )
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( func ), TSID( intrinsic ),
            GetValueType< Value >(),
            sema::Quote( BuildBuiltinFuncParamTypeList< T... >() ),
            static_pointer_cast< void >( fvi ), TERM( 0U )
        ) ) );
        return type;
    }

Changes to bs/builtins/types/localvar/drop.cpp.
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
                if( lv.name() == ""_sid )
                    return;

                // Make the variable visible from the current scope (the parent scope of the statement)
                auto identity = AppendToVectorTerm( c.identity(), lv.name() );

                c.env()->storeValue( identity, ANYTERM( _ ),
                    ValueToIRExpr( v ) );

                // Extend the variable's lifetime, so that it won't be destroyed as the statement's lifetime scope ends,
                // but instead when its parent lifetime scope ends.
                if( c.codeBuilder() )
                    c.codeBuilder()->extendValueLifetime( lv.index() );
            } );
    }







|







20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
                if( lv.name() == ""_sid )
                    return;

                // Make the variable visible from the current scope (the parent scope of the statement)
                auto identity = AppendToVectorTerm( c.identity(), lv.name() );

                c.env()->storeValue( identity, ANYTERM( _ ),
                    ValueToEIR( v ) );

                // Extend the variable's lifetime, so that it won't be destroyed as the statement's lifetime scope ends,
                // but instead when its parent lifetime scope ends.
                if( c.codeBuilder() )
                    c.codeBuilder()->extendValueLifetime( lv.index() );
            } );
    }
Changes to bs/builtins/types/localvar/invoke.cpp.
27
28
29
30
31
32
33
34
35
36
37
38
39
                return sema::GetInvocationRule( *c.env(), val )->resolveInvocation( c, locationId, val, args );
            }
    };

    void SetupLocalVarInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToIRExpr( Value(
                GetValueType< LocalVar >( ANYTERM( _ ) ),
                ANYTERM( _ ) ) ),
            make_shared< LocVarInvocationRule >() );
    }
}







|





27
28
29
30
31
32
33
34
35
36
37
38
39
                return sema::GetInvocationRule( *c.env(), val )->resolveInvocation( c, locationId, val, args );
            }
    };

    void SetupLocalVarInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToEIR( Value(
                GetValueType< LocalVar >( ANYTERM( _ ) ),
                ANYTERM( _ ) ) ),
            make_shared< LocVarInvocationRule >() );
    }
}
Changes to bs/builtins/types/localvar/localvar.cpp.
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
        auto bb = cfg->currentBB();
        if( !bb )
            return PoisonValue();

        // If the type is a tuple of type, transform it into the type of a tuple.
        // I'm hoping that I'm just a huge idiot and not seeing a more obvious and
        // simpler way that would avoid this confusing distinction...
        Value typeVal = *ValueFromIRExpr( type );

        if( IsTuple( typeVal ) )
            typeVal = TupleOfTypesToTupleType( *ValueFromIRExpr( type ) );

        LocalVar lv( name, ValueToIRExpr( typeVal ), index );
        bb->emplace_back( AllocVar( typeVal, index ) );

        Value initResult;

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








|


|

|







30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
        auto bb = cfg->currentBB();
        if( !bb )
            return PoisonValue();

        // If the type is a tuple of type, transform it into the type of a tuple.
        // I'm hoping that I'm just a huge idiot and not seeing a more obvious and
        // simpler way that would avoid this confusing distinction...
        Value typeVal = *ValueFromEIR( type );

        if( IsTuple( typeVal ) )
            typeVal = TupleOfTypesToTupleType( *ValueFromEIR( type ) );

        LocalVar lv( name, ValueToEIR( typeVal ), index );
        bb->emplace_back( AllocVar( typeVal, index ) );

        Value initResult;

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

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
                MakeTuple( move( initResult ) ) );
        }

        auto locVar = ToValue( lv );
        auto identity = AppendToVectorTerm( c.identity(), name );

        c.env()->storeValue( identity, ANYTERM( _ ),
            ValueToIRExpr( locVar ) );

        cb->pushLiveValue( locVar, lv.index() );
        return locVar;
    }

    Value DeclareLocalVarWithTypeInference( Context& c, const Term& typeTExpr, StringId name, const Value& initVal )
    {







|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
                MakeTuple( move( initResult ) ) );
        }

        auto locVar = ToValue( lv );
        auto identity = AppendToVectorTerm( c.identity(), name );

        c.env()->storeValue( identity, ANYTERM( _ ),
            ValueToEIR( locVar ) );

        cb->pushLiveValue( locVar, lv.index() );
        return locVar;
    }

    Value DeclareLocalVarWithTypeInference( Context& c, const Term& typeTExpr, StringId name, const Value& initVal )
    {
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
        // Where pat is the TNamedDecl's type pattern and initValType is the initialization
        // expression's type.

        // We construct the above expressions and unify them. The best solution (if any)
        // will give us the wanted type and the function to invoke to initialize it.

        // Create the _ texpr.
        static auto anyTVar = ValueToIRExpr( ToValue( TVar( "_"_sid ) ) );

        // The $T texpr.
        static auto TTVar = ValueToIRExpr( ToValue( TVar( "T"_sid ) ) );

        // Create the MutRef[$T] param.
        static auto mutRefParamPattern = ValueToIRExpr( ToValue( TNamedDecl( GetValueType< Reference >( TTVar, TSID( mut ) ), "ref"_sid ) ) );

        auto initValParamPattern = ValueToIRExpr( ToValue( Decl( initVal.type(), "initVal"_sid ) ) );

        // Create the _ ( MutRef[pat], initType ) initFunc param.
        auto initFuncTFTParam = ValueToIRExpr( ToValue(
            TNamedDecl( ValueToIRExpr( ToValue( TFuncType( anyTVar, VEC( move( mutRefParamPattern ), move( initValParamPattern ) ),
            make_shared< vector< TermLoc > >(), make_shared< vector< TermLoc > >() ) ) ), "initFunc"_sid ) ) );

        // Create our parameter list pattern.
        auto paramPat = VEC(
            *BuildTemplateSignature( c, TTVar ),
            *BuildTemplateSignature( c, initFuncTFTParam )
        );

        // Create our arg list pattern.
        auto args = VEC(
            *BuildTemplateArgPattern( c, typeTExpr ),
            ValueToIRExpr( ToValue( c.env()->extInitialize() ) )
        );

        auto us = FindBestTyping( paramPat, args, c );

        if( holds_alternative< NoUnification >( us ) )
        {
            // TODO display details







|


|


|

|


|
|











|







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
        // Where pat is the TNamedDecl's type pattern and initValType is the initialization
        // expression's type.

        // We construct the above expressions and unify them. The best solution (if any)
        // will give us the wanted type and the function to invoke to initialize it.

        // Create the _ texpr.
        static auto anyTVar = ValueToEIR( ToValue( TVar( "_"_sid ) ) );

        // The $T texpr.
        static auto TTVar = ValueToEIR( ToValue( TVar( "T"_sid ) ) );

        // Create the MutRef[$T] param.
        static auto mutRefParamPattern = ValueToEIR( ToValue( TNamedDecl( GetValueType< Reference >( TTVar, TSID( mut ) ), "ref"_sid ) ) );

        auto initValParamPattern = ValueToEIR( ToValue( Decl( initVal.type(), "initVal"_sid ) ) );

        // Create the _ ( MutRef[pat], initType ) initFunc param.
        auto initFuncTFTParam = ValueToEIR( ToValue(
            TNamedDecl( ValueToEIR( ToValue( TFuncType( anyTVar, VEC( move( mutRefParamPattern ), move( initValParamPattern ) ),
            make_shared< vector< TermLoc > >(), make_shared< vector< TermLoc > >() ) ) ), "initFunc"_sid ) ) );

        // Create our parameter list pattern.
        auto paramPat = VEC(
            *BuildTemplateSignature( c, TTVar ),
            *BuildTemplateSignature( c, initFuncTFTParam )
        );

        // Create our arg list pattern.
        auto args = VEC(
            *BuildTemplateArgPattern( c, typeTExpr ),
            ValueToEIR( ToValue( c.env()->extInitialize() ) )
        );

        auto us = FindBestTyping( paramPat, args, c );

        if( holds_alternative< NoUnification >( us ) )
        {
            // TODO display details
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
            Vec(
                SubTerm(),  // locvar
                SubTerm()   // initializer
            )
        );

        auto&& [type, initializer] = *callDecomp;
        auto initializerVal = *ValueFromIRExpr( initializer );

        auto index = cfg->getNewTemporaryIndex();

        // Retrieve the texpr's location and set it on the inferred type. This way if an
        // error occurs later with it, for instance when calling LowerTypeForRuntime on it during codegen,
        // it will have a meaningful location for the error message to attach itself on.
        uint32_t typeLoc = ValueFromIRExpr( typeTExpr )->locationId();
        LocalVar lv( name, type, index );

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

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

        auto initResult = ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
            MakeTuple( ToValue( lv ), initVal ) );

        if( !initResult.isConstant() && cir::CanValueBeEagerlyEvaluated( initResult ) )







|






|


|







162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
            Vec(
                SubTerm(),  // locvar
                SubTerm()   // initializer
            )
        );

        auto&& [type, initializer] = *callDecomp;
        auto initializerVal = *ValueFromEIR( initializer );

        auto index = cfg->getNewTemporaryIndex();

        // Retrieve the texpr's location and set it on the inferred type. This way if an
        // error occurs later with it, for instance when calling LowerTypeForRuntime on it during codegen,
        // it will have a meaningful location for the error message to attach itself on.
        uint32_t typeLoc = 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 = ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
            MakeTuple( ToValue( lv ), initVal ) );

        if( !initResult.isConstant() && cir::CanValueBeEagerlyEvaluated( initResult ) )
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

        auto locVar = ToValue( lv );

        if( name != ""_sid )
        {
            auto identity = AppendToVectorTerm( c.identity(), name );
            c.env()->storeValue( identity, ANYTERM( _ ),
                ValueToIRExpr( locVar ) );
        }

        cb->pushLiveValue( locVar, lv.index() );
        return locVar;
    }
}








|







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

        auto locVar = ToValue( lv );

        if( name != ""_sid )
        {
            auto identity = AppendToVectorTerm( c.identity(), name );
            c.env()->storeValue( identity, ANYTERM( _ ),
                ValueToEIR( locVar ) );
        }

        cb->pushLiveValue( locVar, lv.index() );
        return locVar;
    }
}

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

        auto&& [type] = *result;
        return LocalVarType( move( type ) );
    }

    Term Bridge< LocalVar >::Type( const Term& type )
    {
        return ValueToIRExpr( ToValue< LocalVarType >( type ) );
    }

    Value Bridge< LocalVar >::ToValue( const LocalVar& lv )
    {
        return Value( Type( lv.type() ), VEC( TERM( lv.name() ), TERM( lv.index() ) ) );
    }

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

        auto t = FromValue< LocalVarType >( *ValueFromIRExpr( v.type() ) );
        if( !t )
            return nullopt;

        auto result = Decompose( v.val(),
            Vec(
                Val< StringId >(),
                Val< uint32_t >()







|












|







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

        auto&& [type] = *result;
        return LocalVarType( move( type ) );
    }

    Term Bridge< LocalVar >::Type( const Term& type )
    {
        return ValueToEIR( ToValue< LocalVarType >( type ) );
    }

    Value Bridge< LocalVar >::ToValue( const LocalVar& lv )
    {
        return Value( Type( lv.type() ), VEC( TERM( lv.name() ), TERM( lv.index() ) ) );
    }

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

        auto t = FromValue< LocalVarType >( *ValueFromEIR( v.type() ) );
        if( !t )
            return nullopt;

        auto result = Decompose( v.val(),
            Vec(
                Val< StringId >(),
                Val< uint32_t >()
Changes to bs/builtins/types/localvar/typecheck.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"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupLocalVarTypeChecking( Env& e )
    {
        auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );

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

        // LocalVar type checking against another LocalVar: unify their types.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( localVarPattern ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                localVarPattern,
                ANYTERM( _ ) ) ),

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

                auto rhsVal = *ValuePatternFromIRExpr( rhs );
                auto rvarType = *FromValue< LocalVarType >( *ValueFromIRExpr( rhsVal.type() ) );

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












|







|






|


|



|





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"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupLocalVarTypeChecking( Env& e )
    {
        auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );

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

        // LocalVar type checking against another LocalVar: unify their types.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( localVarPattern ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                localVarPattern,
                ANYTERM( _ ) ) ),

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

                auto rhsVal = *ValuePatternFromIRExpr( 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() ) ), 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
52
53
54
55
56
#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( _ ), ValueToIRExpr( 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 > >( *ValueFromIRExpr( result ) );

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

            case sema::Env::Status::AmbiguousMatch:
                throw logic_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 > >( *ValueFromIRExpr( result ) );

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

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










|












|




















|




|







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
52
53
54
55
56
#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:
                throw logic_error( format( "fatal: overload set {} not found", name ) );

            case sema::Env::Status::AmbiguousMatch:
                throw logic_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;
            }

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

Changes to bs/builtins/types/overloadset/invoke.cpp.
67
68
69
70
71
72
73
74
75
76
77
78
79
        static ptr< InvocationRule > pRule = make_shared< OverloadSetInvocationRule >();
        return pRule;
    }

    void SetupOverloadSetInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToIRExpr( Value(
                GetValueType< ptr< OverloadSet > >(),
                ANYTERM( _ ) ) ),
            GetOverloadSetInvocationRule() );
    }
}







|





67
68
69
70
71
72
73
74
75
76
77
78
79
        static ptr< InvocationRule > pRule = make_shared< OverloadSetInvocationRule >();
        return pRule;
    }

    void SetupOverloadSetInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToEIR( Value(
                GetValueType< ptr< OverloadSet > >(),
                ANYTERM( _ ) ) ),
            GetOverloadSetInvocationRule() );
    }
}
Changes to bs/builtins/types/overloadset/overloadset.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "builtins/builtins.h"

using namespace goose::builtins;

bool goose::builtins::IsOverloadSet( const Value& os )
{
    return os.type() == GetValueType< ptr< OverloadSet > >();
}

namespace goose::eir
{
    const Term& Bridge< ptr< builtins::OverloadSet > >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( overloadset ) ) ) );
        return type;
    }

    Value Bridge< ptr< builtins::OverloadSet > >::ToValue( const ptr< builtins::OverloadSet >& os )
    {
        return Value( Type(), TERM( static_pointer_cast< void >( os ) ) );
    }













|







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

using namespace goose::builtins;

bool goose::builtins::IsOverloadSet( const Value& os )
{
    return os.type() == GetValueType< ptr< OverloadSet > >();
}

namespace goose::eir
{
    const Term& Bridge< ptr< builtins::OverloadSet > >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( overloadset ) ) ) );
        return type;
    }

    Value Bridge< ptr< builtins::OverloadSet > >::ToValue( const ptr< builtins::OverloadSet >& os )
    {
        return Value( Type(), TERM( static_pointer_cast< void >( os ) ) );
    }
Changes to bs/builtins/types/overloadset/typecheck.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
52
53
54
55
56
57
58
59
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupOverloadSetTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / overloadset arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( move( funcTypePat ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                GetValueType< ptr< builtins::OverloadSet > >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

            auto cpdecomp = Decompose( callPat,
                Vec(
                    SubTerm(),
                    SubTerm()
                )
            );
            assert( cpdecomp );

            auto&& [argPat, rtPat] = *cpdecomp;

            auto rhsVal = *ValueFromIRExpr( 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();









|


|







|


















|











|







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
52
53
54
55
56
57
58
59
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupOverloadSetTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );

        auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / overloadset arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( move( funcTypePat ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< ptr< builtins::OverloadSet > >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

            auto cpdecomp = Decompose( callPat,
                Vec(
                    SubTerm(),
                    SubTerm()
                )
            );
            assert( cpdecomp );

            auto&& [argPat, rtPat] = *cpdecomp;

            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();
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
                    {
                        tcc.setRHSNamespaceIndex( localNSId );
                        auto func = overload.pInvRule->prepareFunc( tcc.context(), rhsLocId, *overload.callee, t, tcc.flip() );

                        if( func.isPoison() )
                            return nullopt;

                        return ValueToIRExpr( move( func ) );
                    } );

                co_yield { move( wrapped ), tcc };
            }
        } );

        // tfunc type param / overloadset arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                move( tFuncTypePat ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                GetValueType< ptr< builtins::OverloadSet > >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

            auto cpdecomp = Decompose( *callPat,
                Vec(
                    SubTerm(),
                    SubTerm()
                )
            );
            assert( cpdecomp );

            auto&& [argPat, rtPat] = *cpdecomp;

            auto rhsVal = *ValueFromIRExpr( 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();







|









|




|


















|












|







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
                    {
                        tcc.setRHSNamespaceIndex( localNSId );
                        auto func = overload.pInvRule->prepareFunc( tcc.context(), rhsLocId, *overload.callee, t, tcc.flip() );

                        if( func.isPoison() )
                            return nullopt;

                        return ValueToEIR( move( func ) );
                    } );

                co_yield { move( wrapped ), tcc };
            }
        } );

        // tfunc type param / overloadset arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                move( tFuncTypePat ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< ptr< builtins::OverloadSet > >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

            auto cpdecomp = Decompose( *callPat,
                Vec(
                    SubTerm(),
                    SubTerm()
                )
            );
            assert( cpdecomp );

            auto&& [argPat, rtPat] = *cpdecomp;

            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();
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
                    {
                        tcc.setRHSNamespaceIndex( localNSId );
                        auto func = overload.pInvRule->prepareFunc( tcc.context(), rhsLocId, *overload.callee, t, tcc.flip() );

                        if( func.isPoison() )
                            return nullopt;

                        return ValueToIRExpr( move( func ) );
                    } );

                co_yield { move( wrapped ), tcc };
            }
        } );
    }
}







|







151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
                    {
                        tcc.setRHSNamespaceIndex( localNSId );
                        auto func = overload.pInvRule->prepareFunc( tcc.context(), rhsLocId, *overload.callee, t, tcc.flip() );

                        if( func.isPoison() )
                            return nullopt;

                        return ValueToEIR( move( func ) );
                    } );

                co_yield { move( wrapped ), tcc };
            }
        } );
    }
}
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 = ValueFromIRExpr( type ); typeVal && IsTuple( *typeVal ) )
            return ValueToIRExpr( Value( ValueToIRExpr( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );

        return ValueToIRExpr( 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 = ValueFromIRExpr( type ); typeVal && IsTuple( *typeVal ) )
            return ValueToIRExpr( ValuePattern( HOLE( "_"_sid ), ValueToIRExpr( TupleOfTypesToTupleType( *typeVal ) ), HOLE( "_"_sid ) ) );

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

#endif










|
|

|







|
|

|




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 ) ) );
    }
}

#endif
Changes to bs/builtins/types/reference/parse.cpp.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( p.resolver()->currentLocation(),
                    "expected a type.", 0 );
                p.pushValue( PoisonValue() );
                return true;
            }

            ReferenceType rt( ValueToIRExpr( *type ), move( bhv ) );
            p.pushValue( ToValue( rt ) );
            return true;
        };

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







|






|



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
            {
                DiagnosticsManager::GetInstance().emitSyntaxErrorMessage( p.resolver()->currentLocation(),
                    "expected a type.", 0 );
                p.pushValue( PoisonValue() );
                return true;
            }

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

        Rule r( parseRefType );
        auto ruleVal = ToValue( move( r ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( ref ) ), ANYTERM( _ ), ruleTerm );
    }
}
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( ValueFromIRExpr( 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( ValueFromEIR( t )->val(),
            Vec(
                Lit( "reference"_sid ),
                SubTerm(),
                SubTerm()
            )
        );

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

        auto&& [bhv, type] = *result;
        return ReferenceType( move( type ), move( bhv ) );
    }

    Term Bridge< builtins::Reference >::Type( const Term& type, const Term& bhv )
    {
        return ValueToIRExpr( ::ToValue( ReferenceType( type, bhv ) ) );
    }

    Value Bridge< builtins::Reference >::ToValue( const builtins::Reference& ref )
    {
        return BuildComputedValue( ValueToIRExpr( ::ToValue( ref.type() ) ), cir::CalcAddress{ ref.address() } );
    }

    optional< builtins::Reference > Bridge< builtins::Reference >::FromValue( const Value& v )
    {
        if( v.isConstant() )
            return nullopt;

        auto cirRef = get_if< cir::CalcAddress >( &v.cir()->content() );
        if( !cirRef )
            return nullopt;

        auto t = FromValue< ReferenceType >( *ValueFromIRExpr( v.type() ) );
        if( !t )
            return nullopt;

        return builtins::Reference( move( *t ), get< cir::CalcAddress >( v.cir()->content() ) );
    }
}







|




|











|






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

        auto&& [bhv, type] = *result;
        return ReferenceType( move( type ), move( bhv ) );
    }

    Term Bridge< builtins::Reference >::Type( const Term& type, const Term& bhv )
    {
        return ValueToEIR( ::ToValue( ReferenceType( type, bhv ) ) );
    }

    Value Bridge< builtins::Reference >::ToValue( const builtins::Reference& ref )
    {
        return BuildComputedValue( ValueToEIR( ::ToValue( ref.type() ) ), cir::CalcAddress{ ref.address() } );
    }

    optional< builtins::Reference > Bridge< builtins::Reference >::FromValue( const Value& v )
    {
        if( v.isConstant() )
            return nullopt;

        auto cirRef = get_if< cir::CalcAddress >( &v.cir()->content() );
        if( !cirRef )
            return nullopt;

        auto t = FromValue< ReferenceType >( *ValueFromEIR( v.type() ) );
        if( !t )
            return nullopt;

        return builtins::Reference( move( *t ), get< cir::CalcAddress >( v.cir()->content() ) );
    }
}
Changes to bs/builtins/types/reference/typecheck.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
52
53
54
55
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupReferenceTypeChecking( Env& e )
    {
        auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );

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

        auto refTypePatternConstant = ValueToIRExpr(
            Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( const ), ANYTERM( _ ) ) ) );

        auto refTypePatternMutable = ValueToIRExpr(
            Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( mut ), ANYTERM( _ ) ) ) );

        auto refTypePatternTemporary = ValueToIRExpr(
            Value( GetValueType< ReferenceType >(), TVEC( TSID( reference ), TSID( temp ), ANYTERM( _ ) ) ) );

        // Reference type checking rule.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( refTypePattern ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                refTypePattern,
                ANYTERM( _ ) ) ),

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

                auto rhsVal = *ValuePatternFromIRExpr( rhs );
                auto rRefType = *FromValue< ReferenceType >( *ValueFromIRExpr( rhsVal.type() ) );

                // Unify the behaviors
                for( auto&& [b, tcc] : Unify( lRefType.behavior(), rRefType.behavior(), tcc ) )
                {
                    // Unify the types
                    for( auto&& [t, tcc] : Unify( lRefType.type(), rRefType.type(), tcc ) )
                    {
                        co_yield { ValueToIRExpr( ValuePattern( rhsVal.sort(), ValueToIRExpr( ToValue( ReferenceType( t, b ) ) ),
                            rhsVal.val() ) ), tcc };
                    }
                }
            }
        );

        // mut -> const reference unification rule.












|


|


|


|







|






|


|







|







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
52
53
54
55
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;
using namespace goose::cir;

namespace goose::builtins
{
    void SetupReferenceTypeChecking( Env& e )
    {
        auto localVarPattern = GetValueType< LocalVar >( ANYTERM( _ ) );

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

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

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

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

        // Reference type checking rule.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( refTypePattern ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                refTypePattern,
                ANYTERM( _ ) ) ),

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

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

                // Unify the behaviors
                for( auto&& [b, tcc] : Unify( lRefType.behavior(), rRefType.behavior(), tcc ) )
                {
                    // Unify the types
                    for( auto&& [t, tcc] : Unify( lRefType.type(), rRefType.type(), tcc ) )
                    {
                        co_yield { ValueToEIR( ValuePattern( rhsVal.sort(), ValueToEIR( ToValue( ReferenceType( t, b ) ) ),
                            rhsVal.val() ) ), tcc };
                    }
                }
            }
        );

        // mut -> const reference unification rule.
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

        // Reference type checking against a param (implicit dereferencing):
        // Unify the referenced value with the param.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ANYTERM( _ ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                refTypePattern,
                ANYTERM( _ ) ) ),

            []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                auto refval = *ValueFromIRExpr( rhs );
                auto ref = FromValue< Reference >( refval );
                if( !ref )
                    co_return;

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

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

        // LocalVar type checking against a param (implicit referencing):
        // Build a mutable ref value, or just unwrap the locVar if it
        // already contains a ref
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                localVarPattern,
                ANYTERM( _ ) ) ),

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

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

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

            co_yield TypeCheck( lhs, ref, tcc );
        } );

        // Implicit referencing of non-variables: build a tempref
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                refTypePattern,
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        [refTypePattern]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            if( !tcc.context().codeBuilder() )
                co_return;

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

            auto lRefType = *FromValue< ReferenceType >( *ValueFromIRExpr( ValuePatternFromIRExpr( lhs )->type() ) );
            auto lhsPat = ValueToIRExpr( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );

            auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();

            for( auto&& [s,tcc] : TypeCheck( lhsPat, rhs, tcc ) )
            {
                auto valPat = *ValuePatternFromIRExpr( s );
                ReferenceType rt( valPat.type(), TSID( temp ) );

                auto refPat = ValueToIRExpr( ValuePattern( HOLE( "_"_sid ), ValueToIRExpr( ToValue( rt ) ), HOLE( "_"_sid ) ) );

                // TypeCheck the param with the ref
                for( auto&& [s,tcc] : TypeCheck( lhs, refPat, tcc ) )
                {
                    assert( tcc.complexity() >= GetComplexity( ParamPat( refTypePattern ) ) );
                    tcc.subComplexity( GetComplexity( ParamPat( refTypePattern ) ) );

                    auto wrapped = WrapWithPostprocFunc( VEC( s, rhs ),
                    [tempIndex]( const Term& t, TypeCheckingContext tcc ) -> optional< Term >
                    {
                        auto result = Decompose( t,
                            Vec(
                                SubTerm(),
                                SubTerm()
                            )
                        );

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

                        auto rhsVal = *ValueFromIRExpr( rhs );

                        auto refPat = *ValuePatternFromIRExpr( ref );
                        auto rt = *FromValue< ReferenceType >( *ValueFromIRExpr( refPat.type() ) );

                        return ValueToIRExpr( ToValue( Reference{ move( rt ), TemporaryBaseAddr( tempIndex, rhsVal ) } ) );
                    } );

                    co_yield { move( wrapped ), tcc };
                }
            }
        } );
    }
}







|






|




|












|




|








|




|








|




|












|
|








|




















|


|

|








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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209

        // Reference type checking against a param (implicit dereferencing):
        // Unify the referenced value with the param.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ANYTERM( _ ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                refTypePattern,
                ANYTERM( _ ) ) ),

            []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                auto refval = *ValueFromEIR( rhs );
                auto ref = FromValue< Reference >( refval );
                if( !ref )
                    co_return;

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

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

        // LocalVar type checking against a param (implicit referencing):
        // Build a mutable ref value, or just unwrap the locVar if it
        // already contains a ref
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                localVarPattern,
                ANYTERM( _ ) ) ),

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

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

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

            co_yield TypeCheck( lhs, ref, tcc );
        } );

        // Implicit referencing of non-variables: build a tempref
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                refTypePattern,
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        [refTypePattern]( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            if( !tcc.context().codeBuilder() )
                co_return;

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

            auto lRefType = *FromValue< ReferenceType >( *ValueFromEIR( ValuePatternFromIRExpr( lhs )->type() ) );
            auto lhsPat = ValueToEIR( ValuePattern( TSID( param ), lRefType.type(), HOLE( "_"_sid ) ) );

            auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();

            for( auto&& [s,tcc] : TypeCheck( lhsPat, rhs, tcc ) )
            {
                auto valPat = *ValuePatternFromIRExpr( s );
                ReferenceType rt( valPat.type(), TSID( temp ) );

                auto refPat = ValueToEIR( ValuePattern( HOLE( "_"_sid ), ValueToEIR( ToValue( rt ) ), HOLE( "_"_sid ) ) );

                // TypeCheck the param with the ref
                for( auto&& [s,tcc] : TypeCheck( lhs, refPat, tcc ) )
                {
                    assert( tcc.complexity() >= GetComplexity( ParamPat( refTypePattern ) ) );
                    tcc.subComplexity( GetComplexity( ParamPat( refTypePattern ) ) );

                    auto wrapped = WrapWithPostprocFunc( VEC( s, rhs ),
                    [tempIndex]( const Term& t, TypeCheckingContext tcc ) -> optional< Term >
                    {
                        auto result = Decompose( t,
                            Vec(
                                SubTerm(),
                                SubTerm()
                            )
                        );

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

                        auto rhsVal = *ValueFromEIR( rhs );

                        auto refPat = *ValuePatternFromIRExpr( ref );
                        auto rt = *FromValue< ReferenceType >( *ValueFromEIR( refPat.type() ) );

                        return ValueToEIR( ToValue( Reference{ move( rt ), TemporaryBaseAddr( tempIndex, rhsVal ) } ) );
                    } );

                    co_yield { move( wrapped ), tcc };
                }
            }
        } );
    }
}
Changes to bs/builtins/types/runtime/array.cpp.
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
            {
                if( !GetLLVMType( containedType ) )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( containedType.locationId(), "runtime arrays can only contain runtime types." );
                    return PoisonValue();
                }

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

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

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







|





|







13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
            {
                if( !GetLLVMType( containedType ) )
                {
                    DiagnosticsManager::GetInstance().emitErrorMessage( containedType.locationId(), "runtime arrays can only contain runtime types." );
                    return PoisonValue();
                }

                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 )
    {
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
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
#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( _ ), ValueToIRExpr( ToValue( HalfFloatType() ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( float ) ), ANYTERM( _ ), ValueToIRExpr( ToValue( FloatType() ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( double ) ), ANYTERM( _ ), ValueToIRExpr( ToValue( DoubleFloatType() ) ) );

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

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

    const Term& IntegerType::Pattern::GetPattern()
    {
        static auto pattern = ValueToIRExpr( Value( TypeType(), MkStdRTType( TSID( integer ),
            nullptr,
            VEC( HOLE( "size"_sid ), HOLE( "signedness"_sid ) ) ) ) );

        return pattern;
    }

    const Term& IntegerType::PatternSigned::GetPattern()
    {
        static auto pattern = ValueToIRExpr( Value( TypeType(), MkStdRTType( TSID( integer ),
            nullptr,
            VEC( HOLE( "size"_sid ), TERM( 1U ) ) ) ) );

        return pattern;
    }

    const Term& IntegerType::PatternUnsigned::GetPattern()
    {
        static auto pattern = ValueToIRExpr( Value( TypeType(), MkStdRTType( TSID( integer ),
            nullptr,
            VEC( HOLE( "size"_sid ), TERM( 0U ) ) ) ) );

        return pattern;
    }

    const Term& IntegerType::PatternUnsigned32::GetPattern()
    {
        static auto pattern = ValueToIRExpr( Value( TypeType(), MkStdRTType( TSID( integer ),
            nullptr,
            VEC( TERM( 32U ), TERM( 0U ) ) ) ) );

        return pattern;
    }

    llvm::Type* GetLLVMType( const HalfFloatType& t )












|
|
|
















|








|








|








|







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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#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 ) );
            } );

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

    const Term& IntegerType::Pattern::GetPattern()
    {
        static auto pattern = ValueToEIR( Value( TypeType(), MkStdRTType( TSID( integer ),
            nullptr,
            VEC( HOLE( "size"_sid ), HOLE( "signedness"_sid ) ) ) ) );

        return pattern;
    }

    const Term& IntegerType::PatternSigned::GetPattern()
    {
        static auto pattern = ValueToEIR( Value( TypeType(), MkStdRTType( TSID( integer ),
            nullptr,
            VEC( HOLE( "size"_sid ), TERM( 1U ) ) ) ) );

        return pattern;
    }

    const Term& IntegerType::PatternUnsigned::GetPattern()
    {
        static auto pattern = ValueToEIR( Value( TypeType(), MkStdRTType( TSID( integer ),
            nullptr,
            VEC( HOLE( "size"_sid ), TERM( 0U ) ) ) ) );

        return pattern;
    }

    const Term& IntegerType::PatternUnsigned32::GetPattern()
    {
        static auto pattern = ValueToEIR( Value( TypeType(), MkStdRTType( TSID( integer ),
            nullptr,
            VEC( TERM( 32U ), TERM( 0U ) ) ) ) );

        return pattern;
    }

    llvm::Type* GetLLVMType( const HalfFloatType& t )
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
        auto&& [predicates, llvmType, params] = *result;
        auto&& [numBits, signd] = params;
        return IntegerType( numBits, !!signd );
    }

    Term Bridge< APSInt >::Type( const APSInt& i )
    {
        return ValueToIRExpr( eir::ToValue(
            IntegerType( i.getBitWidth(), i.isSigned() ) ) );
    }

    Value Bridge< APSInt >::ToValue( const APSInt& i )
    {
        return Value( Type( i ), TERM( i ) );
    }







|







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
        auto&& [predicates, llvmType, params] = *result;
        auto&& [numBits, signd] = params;
        return IntegerType( numBits, !!signd );
    }

    Term Bridge< APSInt >::Type( const APSInt& i )
    {
        return ValueToEIR( eir::ToValue(
            IntegerType( i.getBitWidth(), i.isSigned() ) ) );
    }

    Value Bridge< APSInt >::ToValue( const APSInt& i )
    {
        return Value( Type( i ), TERM( i ) );
    }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

        return *result;
    }


    const Term& Bridge< uint8_t >::Type()
    {
        static auto type = ValueToIRExpr( eir::ToValue(
            IntegerType( 8, false ) ) );
        return type;
    }

    Value Bridge< uint8_t >::ToValue( uint8_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ).trunc( 8 ) );
    }

    optional< uint8_t > Bridge< uint8_t >::FromValue( const Value& v )
    {
        return FromValue< APSInt >( v )->getLimitedValue();
    }


    const Term& Bridge< uint32_t >::Type()
    {
        static auto type = ValueToIRExpr( eir::ToValue(
            IntegerType( 32, false ) ) );
        return type;
    }

    Value Bridge< uint32_t >::ToValue( uint32_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ).trunc( 32 ) );
    }

    optional< uint32_t > Bridge< uint32_t >::FromValue( const Value& v )
    {
        return FromValue< APSInt >( v )->getLimitedValue();
    }


    const Term& Bridge< uint64_t >::Type()
    {
        static auto type = ValueToIRExpr( eir::ToValue(
            IntegerType( 64, false ) ) );
        return type;
    }

    Value Bridge< uint64_t >::ToValue( uint64_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ) );







|

















|

















|







179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

        return *result;
    }


    const Term& Bridge< uint8_t >::Type()
    {
        static auto type = ValueToEIR( eir::ToValue(
            IntegerType( 8, false ) ) );
        return type;
    }

    Value Bridge< uint8_t >::ToValue( uint8_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ).trunc( 8 ) );
    }

    optional< uint8_t > Bridge< uint8_t >::FromValue( const Value& v )
    {
        return FromValue< APSInt >( v )->getLimitedValue();
    }


    const Term& Bridge< uint32_t >::Type()
    {
        static auto type = ValueToEIR( eir::ToValue(
            IntegerType( 32, false ) ) );
        return type;
    }

    Value Bridge< uint32_t >::ToValue( uint32_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ).trunc( 32 ) );
    }

    optional< uint32_t > Bridge< uint32_t >::FromValue( const Value& v )
    {
        return FromValue< APSInt >( v )->getLimitedValue();
    }


    const Term& Bridge< uint64_t >::Type()
    {
        static auto type = ValueToEIR( eir::ToValue(
            IntegerType( 64, false ) ) );
        return type;
    }

    Value Bridge< uint64_t >::ToValue( uint64_t x )
    {
        return eir::ToValue( APSInt::getUnsigned( x ) );
Changes to bs/builtins/types/runtime/init.cpp.
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

        // Default initialization for integer vars
        RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                auto ref = *FromValue< Reference >( r );

                auto opTypeVal = *ValueFromIRExpr( ref.type().type() );
                auto opType = *FromValue< IntegerType >( opTypeVal );
                auto initVal = Value( ref.type().type(),
                    APSInt( opType.m_numBits, !opType.m_signed ) );

                return BuildComputedValue( GetValueType< void >(),
                    Store( r, initVal ) );
            } );







|







23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

        // Default initialization for integer vars
        RegisterBuiltinFunc< Intrinsic< Value ( IntegerMutRefType ) > >( e, e.extInitialize(),
            []( auto&& c, const Value& r )
            {
                auto ref = *FromValue< Reference >( r );

                auto opTypeVal = *ValueFromEIR( ref.type().type() );
                auto opType = *FromValue< IntegerType >( opTypeVal );
                auto initVal = Value( ref.type().type(),
                    APSInt( opType.m_numBits, !opType.m_signed ) );

                return BuildComputedValue( GetValueType< void >(),
                    Store( r, initVal ) );
            } );
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( _ ), ValueToIRExpr( 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( ValueToIRExpr( pointedType ) ) );
            } );
    }

    llvm::Type* GetLLVMType( const PointerType& p )
    {
        return llvm::PointerType::getUnqual( GetLLVMType( *ValueFromIRExpr( 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( 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 )
    {
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
            return nullopt;

        return NullPointerType();
    }

    const Term& Bridge< NullPointer >::Type()
    {
        static auto type = ValueToIRExpr( eir::ToValue( NullPointerType() ) );
        return type;
    }

    const Value& Bridge< NullPointer >::ToValue( const NullPointer& np )
    {
        static auto val = Value( Type(), TSID( nullptr ) );
        return val;
    }

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

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

        if( !result )
            return nullopt;

        return NullPointer();
    }
}







|











|












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
            return nullopt;

        return NullPointerType();
    }

    const Term& Bridge< NullPointer >::Type()
    {
        static auto type = ValueToEIR( eir::ToValue( NullPointerType() ) );
        return type;
    }

    const Value& Bridge< NullPointer >::ToValue( const NullPointer& np )
    {
        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();
    }
}
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( *ValueFromIRExpr( 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( *ValueFromEIR( mt ) );
            assert( llvmType );
            elements.emplace_back( llvmType );
        }

        return llvm::StructType::get( GetLLVMContext(), elements, rt.m_packed );
    }
}
Changes to bs/builtins/types/runtime/record.h.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
        pvec                m_memberTypes;
        bool                m_packed = false;
    };

    template< typename T, typename V >
    Value CreateRecord( T&& types, V&& vals, bool packed )
    {
        auto rt = ValueToIRExpr( ToValue( RecordType( forward< T >( types ), packed ) ) );
        return Value( move( rt ), forward< V >( vals ) );
    }

    extern llvm::Type* GetLLVMType( const RecordType& rt );
}

namespace goose::eir







|







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
        pvec                m_memberTypes;
        bool                m_packed = false;
    };

    template< typename T, typename V >
    Value CreateRecord( T&& types, V&& vals, bool packed )
    {
        auto rt = ValueToEIR( ToValue( RecordType( forward< T >( types ), packed ) ) );
        return Value( move( rt ), forward< V >( vals ) );
    }

    extern llvm::Type* GetLLVMType( const RecordType& rt );
}

namespace goose::eir
Changes to bs/builtins/types/runtime/typecheck.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
65
66
67
68
69
70
71
72
            VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // ct_int type against a IntegerType type:
        // return the IntegerType type. We don't care if the
        // ct_int fits at this point, this will be dealt with by
        // the ct_int value type checking rule below.
        e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
            ValueToIRExpr( rtIntTypePattern ),
            GetValueType< BigInt >(),
        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            return HalfUnify( lhs, c );
        } );

        // Reject the ct_int param and IntegerType arg pattern,
        // so that it doesn't fall into the rule above which would be incorrect
        // in that case.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( GetValueType< BigInt >() ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( rtIntTypePattern ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            co_return;
        } );

        // ct_integer constant type checking against a IntegerType:
        // Check if the IntegerType is big enough for the constant,
        // and emit a LoadConstantInt cir instruction if so.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( rtIntTypePattern ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                GetValueType< BigInt >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const 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 = *ValueFromIRExpr( rhs );
            if( !rhsVal.isConstant() )
                co_return;

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








|













|

|












|

|


|











|







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
65
66
67
68
69
70
71
72
            VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // ct_int type against a IntegerType type:
        // return the IntegerType type. We don't care if the
        // ct_int fits at this point, this will be dealt with by
        // the ct_int value type checking rule below.
        e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
            ValueToEIR( rtIntTypePattern ),
            GetValueType< BigInt >(),
        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            return HalfUnify( lhs, c );
        } );

        // Reject the ct_int param and IntegerType arg pattern,
        // so that it doesn't fall into the rule above which would be incorrect
        // in that case.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( GetValueType< BigInt >() ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ValueToEIR( rtIntTypePattern ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            co_return;
        } );

        // ct_integer constant type checking against a IntegerType:
        // Check if the IntegerType is big enough for the constant,
        // and emit a LoadConstantInt cir instruction if so.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ValueToEIR( rtIntTypePattern ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< BigInt >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const 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 = ValuePatternFromIRExpr( lhs );
            if( !lhsVal )
                co_return;

86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
                            SubTerm()
                        )
                    );

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

                    auto ct = *FromValue< BigInt >( *ValueFromIRExpr( rhs ) );

                    auto rttypeVal = ValueFromIRExpr( type );
                    assert( rttypeVal );

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

                    APSInt valToLoad;








|

|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
                            SubTerm()
                        )
                    );

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

                    auto ct = *FromValue< BigInt >( *ValueFromEIR( rhs ) );

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

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

                    APSInt valToLoad;

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
182
183
184
185
186
187
188
189
190
                        valToLoad = ct.zext( rttype->m_numBits );
                        valToLoad.setIsSigned( false );
                    }

                    return TERM( valToLoad );
                } );

                co_yield { ValueToIRExpr( Value( s, move( wrapped ) ) ), tcc };
            }
        } );

        auto rtInt8TypePattern = Value( TypeType(), MkStdType( TSID( integer ),
            VEC( TERM( 8U ), ANYTERM( _ ) ) ) );

        auto rtInt8PtrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
            ValueToIRExpr( rtInt8TypePattern ) ) );

        // ct_string type against a char*:
        // return the char* type.
        e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
            ValueToIRExpr( rtInt8PtrTypePattern ),
            GetValueType< string >(),
        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            co_yield HalfUnify( lhs, c );
        } );

        // ct_string constant type checking against a pointer to a integer( 8 ):
        // Emit a LoadConstantStr cir instruction.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( rtInt8PtrTypePattern ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                GetValueType< string >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            auto str = *FromValue< string >( *ValueFromIRExpr( rhs ) );
            auto lhsVal = *ValuePatternFromIRExpr( lhs );

            co_yield { ValueToIRExpr(
                BuildComputedValue( lhsVal.type(), cir::LoadConstStr( str ) ) ), c };
        } );

        auto ptrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
            ANYTERM( _ ) ) );

        // nullptr constant type checking against a pointer of any type;
        // Yield a value of the given pointer type, with a 0 integer as its content.
        // This'll be recognized by codegen to emit a null pointer value of the right type.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( ValueToIRExpr( ptrTypePattern ) ),

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                GetValueType< NullPointer >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            auto lVal = *ValuePatternFromIRExpr( lhs );
            co_yield { ValueToIRExpr( Value( lVal.type(), 0U ) ), c };
        } );
    }
}







|







|




|










|

|


|






|


|











|

|







|



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
182
183
184
185
186
187
188
189
190
                        valToLoad = ct.zext( rttype->m_numBits );
                        valToLoad.setIsSigned( false );
                    }

                    return TERM( valToLoad );
                } );

                co_yield { ValueToEIR( Value( s, move( wrapped ) ) ), tcc };
            }
        } );

        auto rtInt8TypePattern = Value( TypeType(), MkStdType( TSID( integer ),
            VEC( TERM( 8U ), ANYTERM( _ ) ) ) );

        auto rtInt8PtrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
            ValueToEIR( rtInt8TypePattern ) ) );

        // ct_string type against a char*:
        // return the char* type.
        e.typeCheckingRuleSet()->addUnificationRule( TCRINFOS,
            ValueToEIR( rtInt8PtrTypePattern ),
            GetValueType< string >(),
        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            co_yield HalfUnify( lhs, c );
        } );

        // ct_string constant type checking against a pointer to a integer( 8 ):
        // Emit a LoadConstantStr cir instruction.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ValueToEIR( rtInt8PtrTypePattern ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                GetValueType< string >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            auto str = *FromValue< string >( *ValueFromEIR( rhs ) );
            auto lhsVal = *ValuePatternFromIRExpr( lhs );

            co_yield { ValueToEIR(
                BuildComputedValue( lhsVal.type(), cir::LoadConstStr( str ) ) ), c };
        } );

        auto ptrTypePattern = Value( TypeType(), MkStdType( TSID( pointer ),
            ANYTERM( _ ) ) );

        // nullptr constant type checking against a pointer of any type;
        // Yield a value of the given pointer type, with a 0 integer as its content.
        // This'll be recognized by codegen to emit a null pointer value of the right type.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( ValueToEIR( ptrTypePattern ) ),

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                GetValueType< NullPointer >(),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& c ) -> TCGen
        {
            auto lVal = *ValuePatternFromIRExpr( lhs );
            co_yield { ValueToEIR( Value( lVal.type(), 0U ) ), c };
        } );
    }
}
Changes to bs/builtins/types/template/build.cpp.
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
    TFuncType BuildTFuncType( const Value& returnType, const Value& params )
    {
        auto v = make_shared< Vector >();
        v->reserve( TupleSize( params ) );

        ForEachInTuple( params, [&]( auto&& param )
        {
            v->append( ValueToIRExpr( param ) );
            return true;
        } );

        return TFuncType( ValueToIRExpr( returnType ), v,
            make_shared< vector< TermLoc > >(), make_shared< vector< TermLoc > >() );
    }

    optional< Term > BuildTFuncSignature( const Context& c, const TFuncType& tft )
    {
        auto v = make_shared< Vector >();
        v->reserve( VecSize( tft.params() ) );

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

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

        if( !success )
            return nullopt;

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

        return VEC( v, *rtSig );
    }








|



|














|















|







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
    TFuncType BuildTFuncType( const Value& returnType, const Value& params )
    {
        auto v = make_shared< Vector >();
        v->reserve( TupleSize( params ) );

        ForEachInTuple( params, [&]( auto&& param )
        {
            v->append( ValueToEIR( param ) );
            return true;
        } );

        return TFuncType( ValueToEIR( returnType ), v,
            make_shared< vector< TermLoc > >(), make_shared< vector< TermLoc > >() );
    }

    optional< Term > BuildTFuncSignature( const Context& c, const TFuncType& tft )
    {
        auto v = make_shared< Vector >();
        v->reserve( VecSize( tft.params() ) );

        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;
        } );

        if( !success )
            return nullopt;

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

        return VEC( v, *rtSig );
    }

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

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

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

        if( !success )
            return nullopt;

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

        return VEC( apv,*rtArgPat );
    }
}







|















|







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

        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;
        } );

        if( !success )
            return nullopt;

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

        return VEC( apv,*rtArgPat );
    }
}
Changes to bs/builtins/types/template/instantiate.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
            {
                auto p = BuildTemplateParam( c, param, arg );
                instanceParams = AppendToTuple( instanceParams, p );
                return true;
            } );

        // Build the instance function type and identity
        auto returnType = *ValueFromIRExpr( unifiedRType );
        auto instanceType = BuildFuncType( c, returnType, instanceParams );
        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 = *ValueFromIRExpr( result );
                break;

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







|












|







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
            {
                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 );
        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() );
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

                instanceFunc = ToValue( func );

                // TODO: better description including the function's name
                DiagnosticsContext dc( callee.locationId(), "In the template function declared here.", false );

                instanceFunc = CompileFunc( c, instanceFunc );
                c.env()->storeValue( instanceIdentity, ANYTERM( _ ), ValueToIRExpr( instanceFunc ) );
                break;
            }

            case Env::Status::AmbiguousMatch:
                DiagnosticsManager::GetInstance().emitErrorMessage( callee.locationId(),
                    "unexpected ambiguous match when looking up a template function instance." );
                return PoisonValue();
        }

        return instanceFunc;
    }
}







|












75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

                instanceFunc = ToValue( func );

                // TODO: better description including the function's name
                DiagnosticsContext dc( callee.locationId(), "In the template function declared here.", false );

                instanceFunc = CompileFunc( c, instanceFunc );
                c.env()->storeValue( instanceIdentity, ANYTERM( _ ), ValueToEIR( instanceFunc ) );
                break;
            }

            case Env::Status::AmbiguousMatch:
                DiagnosticsManager::GetInstance().emitErrorMessage( callee.locationId(),
                    "unexpected ambiguous match when looking up a template function instance." );
                return PoisonValue();
        }

        return instanceFunc;
    }
}
Changes to bs/builtins/types/template/invoke.cpp.
81
82
83
84
85
86
87
88
89
90
91
92
93
94
        static ptr< InvocationRule > pRule = make_shared< TemplateFunctionInvocationRule >();
        return pRule;
    }

    void SetupTemplateFunctionInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( TSID( constant ),
                ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
                    ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),
            GetTFuncInvocationRule() );
    }
}







|
|





81
82
83
84
85
86
87
88
89
90
91
92
93
94
        static ptr< InvocationRule > pRule = make_shared< TemplateFunctionInvocationRule >();
        return pRule;
    }

    void SetupTemplateFunctionInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToEIR( ValuePattern( TSID( constant ),
                ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
                    ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),
            GetTFuncInvocationRule() );
    }
}
Changes to bs/builtins/types/template/rules.cpp.
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
            return param;
        }

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

    class TNamedDeclTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Value& val ) const final
        {







|







50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
            return param;
        }

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

    class TNamedDeclTemplateRule : public TemplateRule
    {
        optional< Term > buildSignature( const Context& c, const Value& val ) const final
        {
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
            auto tnd = FromValue< TNamedDecl >( val );
            assert( tnd );

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

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

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

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








|







|







92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
            auto tnd = FromValue< TNamedDecl >( 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 Value& val ) const final
        {
            return ValueToEIR( val );
        }

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

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
        }
    };

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

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








|







238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
        }
    };

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

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

269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
            return buildSignature( c, val );
        }
    };

    void SetupTemplateRules( Env& e )
    {
        // Decl
        auto declTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( decl ), ANYTERM( _ ) ) ) );
        e.templateRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( TSID( constant ), declTypePat, ANYTERM( _ ) ) ),
            make_shared< DeclTemplateRule >() );

        // TNamedDecl
        e.templateRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( TSID( constant ), GetValueType< TNamedDecl >(), ANYTERM( _ ) ) ),
            make_shared< TNamedDeclTemplateRule >() );

        // TDecl
        e.templateRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( TSID( constant ), GetValueType< TDecl >(), ANYTERM( _ ) ) ),
            make_shared< TDeclTemplateRule >() );

        // TVar
        e.templateRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( TSID( constant ), GetValueType< TVar >(), ANYTERM( _ ) ) ),
            make_shared< TVarTemplateRule >() );

        // TVec
        e.templateRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( TSID( constant ), GetValueType< TVec >(), ANYTERM( _ ) ) ),
            make_shared< TVecTemplateRule >() );

        // Value
        e.templateRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( TSID( constant ), ANYTERM( _ ), ANYTERM( _ ) ) ),
            make_shared< ValueTemplateRule >() );

        // TFuncType
        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        e.templateRuleSet()->addRule( tFuncTypePat,
            make_shared< TFuncTypeTemplateRule >() );
    }
}







|

|




|




|




|




|




|



|






269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
            return buildSignature( c, val );
        }
    };

    void SetupTemplateRules( Env& e )
    {
        // Decl
        auto declTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( decl ), ANYTERM( _ ) ) ) );
        e.templateRuleSet()->addRule(
            ValueToEIR( ValuePattern( TSID( constant ), declTypePat, ANYTERM( _ ) ) ),
            make_shared< DeclTemplateRule >() );

        // TNamedDecl
        e.templateRuleSet()->addRule(
            ValueToEIR( ValuePattern( TSID( constant ), GetValueType< TNamedDecl >(), ANYTERM( _ ) ) ),
            make_shared< TNamedDeclTemplateRule >() );

        // TDecl
        e.templateRuleSet()->addRule(
            ValueToEIR( ValuePattern( TSID( constant ), GetValueType< TDecl >(), ANYTERM( _ ) ) ),
            make_shared< TDeclTemplateRule >() );

        // TVar
        e.templateRuleSet()->addRule(
            ValueToEIR( ValuePattern( TSID( constant ), GetValueType< TVar >(), ANYTERM( _ ) ) ),
            make_shared< TVarTemplateRule >() );

        // TVec
        e.templateRuleSet()->addRule(
            ValueToEIR( ValuePattern( TSID( constant ), GetValueType< TVec >(), ANYTERM( _ ) ) ),
            make_shared< TVecTemplateRule >() );

        // Value
        e.templateRuleSet()->addRule(
            ValueToEIR( ValuePattern( TSID( constant ), ANYTERM( _ ), ANYTERM( _ ) ) ),
            make_shared< ValueTemplateRule >() );

        // TFuncType
        auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        e.templateRuleSet()->addRule( tFuncTypePat,
            make_shared< TFuncTypeTemplateRule >() );
    }
}
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
20
21
22
23
24
#include "builtins/builtins.h"

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

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

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

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

        // We are replacing lhs with a different terms and re-unifying,
        // so update the complexity accordingly. The structure of the tdecl
        // shouldn't count, only its pattern.
        tcc.subComplexity( GetComplexity( lhs ) );
        tcc.addComplexity( GetComplexity( pat ) );







|




|




|







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

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

    TCGen UnifyTDecl( 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 ) ) );

        // We are replacing lhs with a different terms and re-unifying,
        // so update the complexity accordingly. The structure of the tdecl
        // shouldn't count, only its pattern.
        tcc.subComplexity( GetComplexity( lhs ) );
        tcc.addComplexity( GetComplexity( pat ) );

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
                co_yield { s, tcc };
            }
        }
    }

    void SetupTDeclTypeChecking( Env& e )
    {
        auto tDeclPat = ValueToIRExpr( Value( GetValueType< TDecl >(), VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );

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

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

        // tfunc tdecl param / tfunc arg
        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        auto tDeclTFuncPat = ParamPat( GetValueType< TDecl >(), VEC( tFuncTypePat, ANYTERM( _ ) ) );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            tDeclTFuncPat,

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                move( tFuncTypePat ),
                ANYTERM( _ ) ) ),

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

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

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

            auto rhsVal = *ValueFromIRExpr( rhs );

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

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

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

            auto oldValueRequired = tcc.isValueResolutionRequired();







|




|








|








|






|


|





|





|







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
                co_yield { s, tcc };
            }
        }
    }

    void SetupTDeclTypeChecking( Env& e )
    {
        auto tDeclPat = ValueToEIR( Value( GetValueType< TDecl >(), VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );

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

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

        // tfunc tdecl param / tfunc arg
        auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        auto tDeclTFuncPat = ParamPat( GetValueType< TDecl >(), VEC( tFuncTypePat, ANYTERM( _ ) ) );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            tDeclTFuncPat,

            ValueToEIR( ValuePattern(
                TSID( constant ),
                move( tFuncTypePat ),
                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 ) ) );

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

            auto oldValueRequired = tcc.isValueResolutionRequired();
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
        } );

        // tfunc tdecl param / overloadset arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            move( tDeclTFuncPat ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                GetValueType< ptr< builtins::OverloadSet > >(),
                ANYTERM( _ ) ) ),

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

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

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

            auto rhsVal = *ValueFromIRExpr( rhs );

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

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

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

            auto oldValueRequired = tcc.isValueResolutionRequired();







|






|


|





|





|







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
        } );

        // tfunc tdecl param / overloadset arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            move( tDeclTFuncPat ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                GetValueType< ptr< builtins::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 ) ) );

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

            auto oldValueRequired = tcc.isValueResolutionRequired();
Changes to bs/builtins/types/template/tdecl.cpp.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    }
}

namespace goose::eir
{
    const Term& Bridge< TDecl >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( tdecl ) ) );
        return type;
    }

    Value Bridge< TDecl >::ToValue( const TDecl& td )
    {
        return Value( Type(), VEC( td.type(), TERM( td.name() ) ) );
    }







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    }
}

namespace goose::eir
{
    const Term& Bridge< TDecl >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), TSID( tdecl ) ) );
        return type;
    }

    Value Bridge< TDecl >::ToValue( const TDecl& td )
    {
        return Value( Type(), VEC( td.type(), TERM( td.name() ) ) );
    }
Changes to bs/builtins/types/template/tfunc.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
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"

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

namespace goose::eir
{
    Term Bridge< TFunc >::Type( const builtins::TFunc& tf )
    {
        return ValueToIRExpr( ::ToValue( tf.type() ) );
    }

    Value Bridge< TFunc >::ToValue( const TFunc& tf )
    {
        return Value( Type( tf ), VEC( Quote( tf.signature() ), tf.identity(),
            TERM( tf.toks() ) ) );
    }

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

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











|










|







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
#include "builtins/builtins.h"
#include "lex/lex.h"
#include "parse/parse.h"

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

namespace goose::eir
{
    Term Bridge< TFunc >::Type( const builtins::TFunc& tf )
    {
        return ValueToEIR( ::ToValue( tf.type() ) );
    }

    Value Bridge< TFunc >::ToValue( const TFunc& tf )
    {
        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
Changes to bs/builtins/types/template/tfunctype.cpp.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
        );

        return !!result;
    }

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

namespace goose::eir
{
    const Term& Bridge< TFuncType >::Type()
    {







|







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

        return !!result;
    }

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

namespace goose::eir
{
    const Term& Bridge< TFuncType >::Type()
    {
Changes to bs/builtins/types/template/tnameddecl.cpp.
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
    }
}

namespace goose::eir
{
    const Term& Bridge< TNamedDecl >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), TSID( tnameddecl ) ) );
        return type;
    }

    Value Bridge< TNamedDecl >::ToValue( const TNamedDecl& td )
    {
        return Value( Type(), VEC( td.type(), TERM( td.name() ) ) );
    }







|







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

namespace goose::eir
{
    const Term& Bridge< TNamedDecl >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), TSID( tnameddecl ) ) );
        return type;
    }

    Value Bridge< TNamedDecl >::ToValue( const TNamedDecl& td )
    {
        return Value( Type(), VEC( td.type(), TERM( td.name() ) ) );
    }
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 = ValueFromIRExpr( 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 = ValueFromEIR( te.type() );
        if( !typeVal )
            return false;

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

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

namespace goose::eir
{
    const Term& Bridge< TVar >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tvar ) ) ) );
        return type;
    }

    Value Bridge< TVar >::ToValue( TVar&& td )
    {
        return Value( Type(), TERM( td.name() ) );
    }







|







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

namespace goose::eir
{
    const Term& Bridge< TVar >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tvar ) ) ) );
        return type;
    }

    Value Bridge< TVar >::ToValue( TVar&& td )
    {
        return Value( Type(), TERM( td.name() ) );
    }
Changes to bs/builtins/types/template/tvec.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::eir
{
    const Term& Bridge< TVec >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tvec ) ) ) );
        return type;
    }

    Value Bridge< TVec >::ToValue( const TVec& tv )
    {
        return Value( Type(), tv.content() );
    }








|







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::eir
{
    const Term& Bridge< TVec >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tvec ) ) ) );
        return type;
    }

    Value Bridge< TVec >::ToValue( const TVec& tv )
    {
        return Value( Type(), tv.content() );
    }
Changes to bs/builtins/types/template/tvec.h.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    // 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( ValueFromIRExpr( terms ) ) || ... ) )
            return ValueToIRExpr( ToValue( TVec( move( vec ) ) ) );

        return vec;
    }

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








|
|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    // 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 ValueToEIR( ToValue( TVec( move( vec ) ) ) );

        return vec;
    }

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

Changes to bs/builtins/types/template/typecheck.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
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupTemplateFunctionTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );

        auto tFuncTypePat = ValueToIRExpr( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / tfunc arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( move( funcTypePat ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                tFuncTypePat,
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

            auto rhsVal = *ValueFromIRExpr( 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 );









|


|







|


















|

|







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
#include "builtins/builtins.h"

using namespace goose;
using namespace goose::eir;

namespace goose::builtins
{
    void SetupTemplateFunctionTypeChecking( Env& e )
    {
        auto funcTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( func ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( VA ) ) ) );

        auto tFuncTypePat = ValueToEIR( Value( TypeType(), VEC( TSID( texpr ), TSID( tfunc ),
            ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) );

        // func type param / tfunc arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( move( funcTypePat ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                tFuncTypePat,
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    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 );
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

                    DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ?  "Instantiated here." : "", false );
                    auto ifunc = InstantiateTFunc( tcc.context(), rhsVal, t, tcc.flip() );

                    if( ifunc.isPoison() )
                        return nullopt;

                    return ValueToIRExpr( ifunc );
                } );

                co_yield { move( wrapped ), tcc };
            }
        } );

        // tfunc type param / tfunc arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( tFuncTypePat ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                move( tFuncTypePat ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    SubTerm(),
                    Val< LocationId >()
                )
            );
            assert( ldecomp );

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

            auto rhsVal = *ValueFromIRExpr( 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 );







|











|


















|


|







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

                    DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ?  "Instantiated here." : "", false );
                    auto ifunc = InstantiateTFunc( tcc.context(), rhsVal, t, tcc.flip() );

                    if( ifunc.isPoison() )
                        return nullopt;

                    return ValueToEIR( ifunc );
                } );

                co_yield { move( wrapped ), tcc };
            }
        } );

        // tfunc type param / tfunc arg
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ParamPat( tFuncTypePat ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                move( tFuncTypePat ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto ldecomp = Decompose( lhs,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
                    SubTerm(),
                    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 );
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

                    DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ?  "Instantiated here." : "", false );
                    auto ifunc = InstantiateTFunc( tcc.context(), rhsVal, t, tcc.flip() );

                    if( ifunc.isPoison() )
                        return nullopt;

                    return ValueToIRExpr( ifunc );
                } );

                co_yield { move( wrapped ), tcc };
            }
        } );
    }
}







|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

                    DiagnosticsContext dc( rhsVal.locationId(), rhsVal.locationId() ?  "Instantiated here." : "", false );
                    auto ifunc = InstantiateTFunc( tcc.context(), rhsVal, t, tcc.flip() );

                    if( ifunc.isPoison() )
                        return nullopt;

                    return ValueToEIR( ifunc );
                } );

                co_yield { move( wrapped ), tcc };
            }
        } );
    }
}
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
41
#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 )
    {
        auto lref = *FromValue< Reference >( tupRef );

        uint32_t index = 0;
        auto tupType = *ValueFromIRExpr( lref.type().type() );

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

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

            // Create a mutable reference to the element to initialize
            ReferenceType rt( t, TSID( mut ) );
            auto addr = lref.address();
            addr.appendToPath( index );

            auto elemRef = BuildComputedValue( ValueToIRExpr( ToValue( rt ) ),
                move( addr ) ).setLocationId( elemType.locationId() );

            auto elemInit = *ValueFromIRExpr( 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
41
#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 )
    {
        auto lref = *FromValue< Reference >( tupRef );

        uint32_t index = 0;
        auto tupType = *ValueFromEIR( lref.type().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 addr = lref.address();
            addr.appendToPath( index );

            auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
                move( addr ) ).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(),
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
                CustomPattern< Reference, Reference::PatternMutable< TuplePattern > >
                ) > >( e, e.extInitialize(),
            []( const Context& c, const Value& tupRef )
            {
                auto ref = *FromValue< Reference >( tupRef );

                uint32_t index = 0;
                auto tupType = *ValueFromIRExpr( ref.type().type() );

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

                    // Create a mutable reference to the element to initialize
                    ReferenceType rt( t, TSID( mut ) );
                    auto addr = ref.address();
                    addr.path().back() = index++;

                    auto elemRef = BuildComputedValue( ValueToIRExpr( ToValue( rt ) ),
                        Load( ToValue( ref ), rt.type() ) )
                        .setLocationId( elemType.locationId() );

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








|



|






|







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
                CustomPattern< Reference, Reference::PatternMutable< TuplePattern > >
                ) > >( e, e.extInitialize(),
            []( const Context& c, const Value& tupRef )
            {
                auto ref = *FromValue< Reference >( tupRef );

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

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

                    // Create a mutable reference to the element to initialize
                    ReferenceType rt( t, TSID( mut ) );
                    auto addr = ref.address();
                    addr.path().back() = index++;

                    auto elemRef = BuildComputedValue( ValueToEIR( ToValue( rt ) ),
                        Load( ToValue( ref ), rt.type() ) )
                        .setLocationId( elemType.locationId() );

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

Changes to bs/builtins/types/tuple/lower.cpp.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
            []( const Context& c, const Value& tupType )
        {
            RecordType rt;
            bool success = true;

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

                rt.m_memberTypes->append( ValueToIRExpr( *loweredType ) );
                return true;
            } );

            if( !success )
                return PoisonValue();

            return ToValue( rt );







|






|







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
            []( 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 ) );
                return true;
            } );

            if( !success )
                return PoisonValue();

            return ToValue( rt );
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
                if( !member || member->isPoison() )
                {
                    success = false;
                    return false;
                }

                types->append( member->type() );
                vals->append( ValueToIRExpr( *member ) );
                return true;
            } );

            if( !success )
                return PoisonValue();

            return CreateRecord( move( types ), move( vals ), false );
        } );
    }
}







|










46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
                if( !member || member->isPoison() )
                {
                    success = false;
                    return false;
                }

                types->append( member->type() );
                vals->append( ValueToEIR( *member ) );
                return true;
            } );

            if( !success )
                return PoisonValue();

            return CreateRecord( move( types ), move( vals ), false );
        } );
    }
}
Changes to bs/builtins/types/tuple/tuple.cpp.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    Value MkTupleType( const Term& state, const Term& types )
    {
        return Value( TypeType(), VEC( TSID( tuple ), state, types ) );
    }

    extern Value TupleOfTypesToTupleType( const Value& tup )
    {
        auto typeVal = ValueFromIRExpr( tup.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "tuple"_sid ),
                SubTerm(),
                SubTerm()
            )
        );







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    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()
            )
        );
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    {
        static auto type = MkTupleType( TSID( close ), VEC() );
        return type;
    }

    const Value& EmptyTuple()
    {
        static auto val = Value( ValueToIRExpr( EmptyTupleType() ), VEC() );
        return val;
    }

    const Value& EmptyClosedTuple()
    {
        static auto val = Value( ValueToIRExpr( EmptyClosedTupleType() ), VEC() );
        return val;
    }

    Value ToClosedTupleType( const Value& tuptype )
    {
        auto decomp = Decompose( tuptype.val(),
            Vec(







|





|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    {
        static auto type = MkTupleType( TSID( close ), VEC() );
        return type;
    }

    const Value& EmptyTuple()
    {
        static auto val = Value( ValueToEIR( EmptyTupleType() ), VEC() );
        return val;
    }

    const Value& EmptyClosedTuple()
    {
        static auto val = Value( ValueToEIR( EmptyClosedTupleType() ), VEC() );
        return val;
    }

    Value ToClosedTupleType( const Value& tuptype )
    {
        auto decomp = Decompose( tuptype.val(),
            Vec(
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
                SubTerm(),
                SubTerm()
            )
        );

        auto&& [tupState, tupTypesVec] = *decomp;

        auto newTypeVec = AppendToVectorTerm( tupTypesVec, ValueToIRExpr( type ) );
        auto result = MkTupleType( tupState, newTypeVec );

        if( tuptype.isPoison() || type.isPoison() )
            result.setPoison();

        return result;
    }

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

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

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

        return result;
    }

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

        assert( tupType );
        assert( valType );

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

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

        return result;
    }

    Value PrependToTupleType( const Value& type, const Value& tuptype )
    {
        auto decomp = Decompose( tuptype.val(),
            Vec(
                Lit( "tuple"_sid ),
                SubTerm(),
                SubTerm()
            )
        );

        auto&& [tupState, tupTypesVec] = *decomp;

        auto newTypeVec = PrependToVectorTerm( tupTypesVec, ValueToIRExpr( type ) );
        auto result = MkTupleType( tupState, newTypeVec );

        if( tuptype.isPoison() || type.isPoison() )
            result.setPoison();

        return result;
    }

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

        assert( tupType );
        assert( valType );

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

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

        return result;
    }








|










|



|
|









|
|





|
|



















|










|
|





|
|







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
                SubTerm(),
                SubTerm()
            )
        );

        auto&& [tupState, tupTypesVec] = *decomp;

        auto newTypeVec = AppendToVectorTerm( tupTypesVec, ValueToEIR( type ) );
        auto result = MkTupleType( tupState, newTypeVec );

        if( tuptype.isPoison() || type.isPoison() )
            result.setPoison();

        return result;
    }

    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 PrependToTupleType( const Value& type, const Value& tuptype )
    {
        auto decomp = Decompose( tuptype.val(),
            Vec(
                Lit( "tuple"_sid ),
                SubTerm(),
                SubTerm()
            )
        );

        auto&& [tupState, tupTypesVec] = *decomp;

        auto newTypeVec = PrependToVectorTerm( tupTypesVec, ValueToEIR( type ) );
        auto result = MkTupleType( tupState, newTypeVec );

        if( tuptype.isPoison() || type.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;
    }

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
            result.setPoison();

        return result;
    }

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

        assert( ltupType );
        assert( rtupType );

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

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

        return result;
    }







|
|





|







206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
            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;
    }
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
        );

        return !!result;
    }

    bool IsTuple( const Value& t )
    {
        auto typeVal = ValueFromIRExpr( 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 = ValueFromIRExpr( t.type() );
        auto result = Decompose( typeVal->val(),
            Vec(
                Lit( "tuple"_sid ),
                Lit( "open"_sid ),
                SubTerm()
            )
        );

        return !!result;
    }

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

    size_t TupleTypeSize( const Value& tupType )
    {
        auto decomp = Decompose( tupType.val(),
            Vec(







|




















|













|
|







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
        );

        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 TupleTypeSize( const Value& tupType )
    {
        auto decomp = Decompose( tupType.val(),
            Vec(
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330

        auto&& [tupState, tupTypesVec] = *decomp;
        return tupTypesVec->terms()[index];
    }

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

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







|







316
317
318
319
320
321
322
323
324
325
326
327
328
329
330

        auto&& [tupState, tupTypesVec] = *decomp;
        return tupTypesVec->terms()[index];
    }

    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];
    }
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
        } );

        return result;
    }

    const Term& TuplePattern::GetPattern()
    {
        static auto pattern = ValueToIRExpr( MkTupleType( HOLE( "_"_sid ), HOLE( "_"_sid ) ) );
        return pattern;
    }

    const Term& TupleOpenPattern::GetPattern()
    {
        static auto pattern = ValueToIRExpr( MkTupleType( TSID( open ), HOLE( "_"_sid ) ) );
        return pattern;
    }

    const Term& TuplePatternOfTypeT::GetPattern()
    {
        static auto pattern = ValueToIRExpr( MkTupleType( HOLE( "_"_sid ), HOLE( "T"_sid ) ) );
        return pattern;
    }
}







|





|





|



357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
        } );

        return result;
    }

    const Term& TuplePattern::GetPattern()
    {
        static auto pattern = ValueToEIR( MkTupleType( HOLE( "_"_sid ), HOLE( "_"_sid ) ) );
        return pattern;
    }

    const Term& TupleOpenPattern::GetPattern()
    {
        static auto pattern = ValueToEIR( MkTupleType( TSID( open ), HOLE( "_"_sid ) ) );
        return pattern;
    }

    const Term& TuplePatternOfTypeT::GetPattern()
    {
        static auto pattern = ValueToEIR( MkTupleType( HOLE( "_"_sid ), HOLE( "T"_sid ) ) );
        return pattern;
    }
}
Changes to bs/builtins/types/tuple/tuple.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_BUILTINS_TYPES_TUPLE_INL
#define GOOSE_BUILTINS_TYPES_TUPLE_INL

namespace goose::builtins
{
    template< typename... V >
    Value MakeTuple( V&&... values )
    {
        return Value(
            ValueToIRExpr( MkTupleType( TSID( close ), TERM( Vector::Make( values.type()... ) ) ) ),
            TERM( Vector::Make( ValueToIRExpr( values )... ) ) );
    }

    template< typename F >
    void ForEachInTuple( const Value& tup, F&& func )
    {
        // 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( *ValueFromIRExpr( t ) );
        } );
    }

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









|
|











|







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_BUILTINS_TYPES_TUPLE_INL
#define GOOSE_BUILTINS_TYPES_TUPLE_INL

namespace goose::builtins
{
    template< typename... V >
    Value MakeTuple( V&&... values )
    {
        return Value(
            ValueToEIR( MkTupleType( TSID( close ), TERM( Vector::Make( values.type()... ) ) ) ),
            TERM( Vector::Make( ValueToEIR( values )... ) ) );
    }

    template< typename F >
    void ForEachInTuple( const Value& tup, F&& func )
    {
        // 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(),
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
            return false;

        if( !holds_alternative< pvec >( tup2.val() ) )
            return false;

        return ForEachInVectorTerms( tup1.val(), tup2.val(), [&]( auto&& t1, auto&& t2 )
        {
            return func( *ValueFromIRExpr( t1 ), *ValueFromIRExpr( t2 ) );
        } );
    }
}

namespace goose::eir
{
    // Type
    static inline const Value& BuildTupleType( const Value& typeSoFar )
    {
        return typeSoFar;
    }

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

    template< typename... T >
    const Term& Bridge< tuple< T... > >::Type()
    {
        if constexpr( sizeof... ( T ) == 0 )
        {
            static auto type = ValueToIRExpr( builtins::EmptyClosedTupleType() );
            return type;
        }
        else
        {
            static auto type = ValueToIRExpr( BuildTupleType< T... >( builtins::EmptyClosedTupleType() ) );
            return type;
        }
    }

    // Val
    template< typename T, size_t... I >
    auto BuildTupleValue( const T& tup, index_sequence< I... > )
    {
        return VEC( ValueToIRExpr( ToValue( get< I >( tup ) ) )... );
    }

    template< typename... T >
    Value Bridge< tuple< T... > >::ToValue( const tuple< T... >& x )
    {
        auto val = BuildTupleValue( x, index_sequence_for< T... >() );
        return Value( Type(), move( val ) );
    }

    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( ValueFromIRExpr( 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;








|


















|


|







|




|








|
















|







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
            return false;

        if( !holds_alternative< pvec >( tup2.val() ) )
            return false;

        return ForEachInVectorTerms( tup1.val(), tup2.val(), [&]( auto&& t1, auto&& t2 )
        {
            return func( *ValueFromEIR( t1 ), *ValueFromEIR( t2 ) );
        } );
    }
}

namespace goose::eir
{
    // Type
    static inline const Value& BuildTupleType( const Value& typeSoFar )
    {
        return typeSoFar;
    }

    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 )
        {
            static auto type = ValueToEIR( builtins::EmptyClosedTupleType() );
            return type;
        }
        else
        {
            static auto type = ValueToEIR( BuildTupleType< T... >( builtins::EmptyClosedTupleType() ) );
            return type;
        }
    }

    // Val
    template< typename T, size_t... I >
    auto BuildTupleValue( const T& tup, index_sequence< I... > )
    {
        return VEC( ValueToEIR( ToValue( get< I >( tup ) ) )... );
    }

    template< typename... T >
    Value Bridge< tuple< T... > >::ToValue( const tuple< T... >& x )
    {
        auto val = BuildTupleValue( x, index_sequence_for< T... >() );
        return Value( Type(), move( val ) );
    }

    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;

Changes to bs/builtins/types/tuple/typecheck.cpp.
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
147
148
149
150
151
152
153
154
155
156
157
158
159
        for( auto&& [s,tcc] : TypeCheck( param, arg, tcc ) )
        {
            auto val = ValuePatternFromIRExpr( s );
            assert( val );
            auto newOut = AppendToTuple( out, *val );

            if( index == ( tupSize - 1 ) )
                co_yield { ValueToIRExpr( newOut ), tcc };
            else
                co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
        }
    }

    TCGen TypeCheckComputedTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, const cir::CalcAddress& tupAddr, uint32_t index, const Value& out )
    {
        auto param = ParamPat( GetTupleTypeElement( tupType, index ) );

        auto argType = GetTupleElementType( tupArg, index );
        ReferenceType rt( argType, TSID( const ) );
        auto argAddr = tupAddr;
        argAddr.appendToPath( index );

        auto argRef = ValueToIRExpr( BuildComputedValue( ValueToIRExpr( ToValue( rt ) ),
            move( argAddr ) ) );

        auto tupSize = TupleTypeSize( tupType );

        for( auto&& [s,tcc] : TypeCheck( param, argRef, tcc ) )
        {
            auto val = ValuePatternFromIRExpr( s );
            assert( val );
            auto newOut = AppendToTuple( out, *val );

            if( index == ( tupSize - 1 ) )
                co_yield { ValueToIRExpr( newOut ), tcc };
            else
                co_yield TypeCheckComputedTuple( tcc, tupType, tupArg, tupAddr, index + 1, newOut );
        }
    }

    void SetupTupleTypeChecking( Env& e )
    {
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                VECOFLENGTH( L ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltup = ValuePatternFromIRExpr( lhs );
            auto rtup = ValueFromIRExpr( rhs );

            if( !ltup || !rtup )
                co_return;

            auto tupType = *ValueFromIRExpr( ltup->type() );
            assert( TupleTypeSize( tupType ) == TupleSize( *rtup ) );

            co_yield TypeCheckConstantTuple( tcc, tupType, *rtup, 0, EmptyTuple() );
        } );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                TSID( computed ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltup = ValuePatternFromIRExpr( lhs );
            auto rtup = ValueFromIRExpr( rhs );

            if( !ltup || !rtup || !tcc.context().codeBuilder() )
                co_return;

            auto tupType = *ValueFromIRExpr( ltup->type() );
            assert( TupleTypeSize( tupType ) == TupleTypeSize( *ValueFromIRExpr( rtup->type() ) ) );

            auto tempIndex = tcc.context().codeBuilder()->cfg()->getNewTemporaryIndex();
            cir::CalcAddress addr( cir::TemporaryBaseAddr( tempIndex, *rtup ) );

            co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, addr, 0, EmptyTuple() );
        } );

        // Single element tuple unwrapping rules: if we encounter such a tuple, attempt to typecheck
        // its contained value with whatever's on the other side.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto tup = ValueFromIRExpr( rhs );
            if( !tup )
                co_return;

            const auto& vec1 = *get< pvec >( tup->val() );
            co_yield TypeCheck( lhs, vec1[0], tcc );
        } );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern(
                TSID( constant ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto tup = ValueFromIRExpr( 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.







|














|











|









|

|


|

|





|




|







|

|


|

|





|




|
|











|




|

|




|









|

|


|






|







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
147
148
149
150
151
152
153
154
155
156
157
158
159
        for( auto&& [s,tcc] : TypeCheck( param, arg, tcc ) )
        {
            auto val = ValuePatternFromIRExpr( s );
            assert( val );
            auto newOut = AppendToTuple( out, *val );

            if( index == ( tupSize - 1 ) )
                co_yield { ValueToEIR( newOut ), tcc };
            else
                co_yield TypeCheckConstantTuple( tcc, tupType, tupArg, index + 1, newOut );
        }
    }

    TCGen TypeCheckComputedTuple( const TypeCheckingContext& tcc, const Value& tupType, const Value& tupArg, const cir::CalcAddress& tupAddr, uint32_t index, const Value& out )
    {
        auto param = ParamPat( GetTupleTypeElement( tupType, index ) );

        auto argType = GetTupleElementType( tupArg, index );
        ReferenceType rt( argType, TSID( const ) );
        auto argAddr = tupAddr;
        argAddr.appendToPath( index );

        auto argRef = ValueToEIR( BuildComputedValue( ValueToEIR( ToValue( rt ) ),
            move( argAddr ) ) );

        auto tupSize = TupleTypeSize( tupType );

        for( auto&& [s,tcc] : TypeCheck( param, argRef, tcc ) )
        {
            auto val = ValuePatternFromIRExpr( s );
            assert( val );
            auto newOut = AppendToTuple( out, *val );

            if( index == ( tupSize - 1 ) )
                co_yield { ValueToEIR( newOut ), tcc };
            else
                co_yield TypeCheckComputedTuple( tcc, tupType, tupArg, tupAddr, index + 1, newOut );
        }
    }

    void SetupTupleTypeChecking( Env& e )
    {
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern(
                TSID( constant ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VECOFLENGTH( L ) ) ),
                VECOFLENGTH( L ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            auto ltup = ValuePatternFromIRExpr( 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 = ValuePatternFromIRExpr( 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();
            cir::CalcAddress addr( cir::TemporaryBaseAddr( tempIndex, *rtup ) );

            co_yield TypeCheckComputedTuple( tcc, tupType, *rtup, addr, 0, EmptyTuple() );
        } );

        // Single element tuple unwrapping rules: if we encounter such a tuple, attempt to typecheck
        // its contained value with whatever's on the other side.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ANYTERM( _ ),
                ANYTERM( _ ) ) ),

            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 );
        } );

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),

            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.
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        // When unifying a tuple against a value whose type is a hole, we don't want
        // the above rule to apply (ie we don't want 1 element tuples bound to generic
        // template parameters to be peeled off). So here's a rule for this case which
        // leaves the tuple unchanged. It will take priority over the above rule in
        // those cases because it matches a more specific pattern.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToIRExpr( ValuePattern(
                ANYTERM( _ ),
                ValueToIRExpr( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),

            ValueToIRExpr( ValuePattern( ANYTERM( _ ), HolePattern(), ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            co_yield { lhs, tcc };
        } );
    }
}







|

|


|







172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
        // When unifying a tuple against a value whose type is a hole, we don't want
        // the above rule to apply (ie we don't want 1 element tuples bound to generic
        // template parameters to be peeled off). So here's a rule for this case which
        // leaves the tuple unchanged. It will take priority over the above rule in
        // those cases because it matches a more specific pattern.
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS,

            ValueToEIR( ValuePattern(
                ANYTERM( _ ),
                ValueToEIR( MkTupleType( ANYTERM( _ ), VEC( ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),

            ValueToEIR( ValuePattern( ANYTERM( _ ), HolePattern(), ANYTERM( _ ) ) ),

        []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            co_yield { lhs, tcc };
        } );
    }
}
Changes to bs/builtins/types/typepredicates.cpp.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
            return true;

        // Create a new identity for the predicate, which imports everything from the parent identity
        // and also makes @val visible as a placeholder for the type's value.
        auto predicatesIdentity = VEC( Env::NewUniqueId() );
        c.env()->addVisibilityRule( parentIdentity, predicatesIdentity );

        auto typeTerm = ValueToIRExpr( type );

        auto name = "@val"_sid;
        auto valuePlaceholderIdentity = AppendToVectorTerm( predicatesIdentity, TERM( name ) );
        c.env()->storeValue( valuePlaceholderIdentity, ANYTERM( _ ),
            ValueToIRExpr( BuildComputedValue( typeTerm, cir::Placeholder( typeTerm, name ) ) ) );

        Context localContext( c.env(), predicatesIdentity );

        for( auto&& toks : tp.m_unparsedPredicates )
        {
            auto tokProvider = lex::MakeVectorAdapter( toks );
            auto r = make_shared< parse::Resolver >( tokProvider, localContext );







|




|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
            return true;

        // Create a new identity for the predicate, which imports everything from the parent identity
        // and also makes @val visible as a placeholder for the type's value.
        auto predicatesIdentity = VEC( Env::NewUniqueId() );
        c.env()->addVisibilityRule( parentIdentity, predicatesIdentity );

        auto typeTerm = ValueToEIR( type );

        auto name = "@val"_sid;
        auto valuePlaceholderIdentity = AppendToVectorTerm( predicatesIdentity, TERM( name ) );
        c.env()->storeValue( valuePlaceholderIdentity, ANYTERM( _ ),
            ValueToEIR( BuildComputedValue( typeTerm, cir::Placeholder( typeTerm, name ) ) ) );

        Context localContext( c.env(), predicatesIdentity );

        for( auto&& toks : tp.m_unparsedPredicates )
        {
            auto tokProvider = lex::MakeVectorAdapter( toks );
            auto r = make_shared< parse::Resolver >( tokProvider, localContext );
Changes to bs/builtins/types/types.cpp.
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    }

    bool IsCompileTimeOnlyValue( const Value& v )
    {
        if( IsBuiltinFunc( v ) || IsIntrinsicFunc( v ) || IsType( v ) )
            return true;

        auto typeVal = *ValueFromIRExpr( v.type() );
        assert( typeVal.isConstant() );
        auto vec = get_if< pvec >( &typeVal.val() );
        if( vec && !( *vec )->terms().empty() && ( *vec )->terms().front() == TSID( ct_type ) )
            return true;

        return false;
    }







|







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
    }

    bool IsCompileTimeOnlyValue( const Value& v )
    {
        if( IsBuiltinFunc( v ) || IsIntrinsicFunc( v ) || IsType( v ) )
            return true;

        auto typeVal = *ValueFromEIR( v.type() );
        assert( typeVal.isConstant() );
        auto vec = get_if< pvec >( &typeVal.val() );
        if( vec && !( *vec )->terms().empty() && ( *vec )->terms().front() == TSID( ct_type ) )
            return true;

        return false;
    }
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( *ValueFromIRExpr( 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( *ValueFromEIR( 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( *ValueFromIRExpr( 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( *ValueFromEIR( arg ) ) )
            {
                argsAreConstant = false;
                return false;
            }

            return true;
        } );
Changes to bs/codegen/instructions.cpp.
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

    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, *ValueFromIRExpr( a ) );
        if( !parg )
            return nullptr;

        args.emplace_back( parg );
    }

    return m_llvmBuilder.CreateCall( llvm::FunctionCallee( llvmCallee ), args );







|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

    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 );
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    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, *ValueFromIRExpr( load.type() ) );
    if( !type )
        return nullptr;

    auto* llvmType = GetLLVMType( *type );
    assert( llvmType );

    auto* ptrVal = buildValue(inf, load.addr() );//  buildAddress( inf, load.addr() );







|







105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
    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 = buildValue(inf, load.addr() );//  buildAddress( 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
74
    {
        return *b ?
            llvm::ConstantInt::getTrue( GetLLVMContext() ) :
            llvm::ConstantInt::getFalse( GetLLVMContext() );
    }
    else if( auto intVal = FromValue< APSInt >( *val ) )
    {
            return llvm::ConstantInt::get( GetLLVMType( *ValueFromIRExpr( val->type() ) ),
            *FromValue< APSInt >( *val ) );
    }
    else if( auto ptType = FromValue< PointerType >( *ValueFromIRExpr( val->type() ) ) )
    {
        // The only kind of pointer constant we can have at the moment are nullptr.
        return llvm::ConstantPointerNull::get( static_cast< llvm::PointerType* >
            ( GetLLVMType( *ValueFromIRExpr( val->type() ) ) ) );
    }
    else if( auto recType = FromValue< RecordType >( *ValueFromIRExpr( 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, *ValueFromIRExpr( 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( *ValueFromIRExpr( 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
74
    {
        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() ) ) )
    {
        // The only kind of pointer constant we can have at the moment are nullptr.
        return llvm::ConstantPointerNull::get( static_cast< llvm::PointerType* >
            ( GetLLVMType( *ValueFromEIR( val->type() ) ) ) );
    }
    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;
}
Changes to bs/eir/value.cpp.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
        static auto poisonType = Value( TypeType(), 0U ).setPoison();
        return poisonType;
    }

    // A generic poisoned value of "poisontype" type.
    const Value& PoisonValue()
    {
        static auto poisonVal = Value( ValueToIRExpr( PoisonType() ), 0U ).setPoison();
        return poisonVal;
    }

    Term ValueToIRExpr( const Value& v )
    {
        if( v.isConstant() )
        {
            // Special case for type's type
            if( v.isType() )
            {
                auto result = Decompose( v.val(),







|



|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
        static auto poisonType = Value( TypeType(), 0U ).setPoison();
        return poisonType;
    }

    // A generic poisoned value of "poisontype" type.
    const Value& PoisonValue()
    {
        static auto poisonVal = Value( ValueToEIR( PoisonType() ), 0U ).setPoison();
        return poisonVal;
    }

    Term ValueToEIR( const Value& v )
    {
        if( v.isConstant() )
        {
            // Special case for type's type
            if( v.isType() )
            {
                auto result = Decompose( v.val(),
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 > ValueFromIRExpr( 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 > ValueFromEIR( const Term& t )
    {
        // Special case for type's type
        auto typedecomp = Decompose( t,
            Vec(
                Lit( "type"_sid ),
                Val< uint32_t >(),
                Val< LocationId >()
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
        auto cir = Decompose( val, Val< ptr< void > >() );
        if( !cir )
            return nullopt;

        return Value( type, static_pointer_cast< cir::Instruction >( ptr< void >( *cir ) ), static_cast< uint32_t >( locationId ) );
    }

    Term ValueToIRExpr( const ValuePattern& v )
    {
        return VEC( TSID( value ), v.sort(), v.type(), v.val(), static_cast< LocationId >( v.locationId() ) );
    }

    optional< ValuePattern > ValuePatternFromIRExpr( const Term& t )
    {
        auto result = Decompose( t,







|







99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
        auto cir = Decompose( val, Val< ptr< void > >() );
        if( !cir )
            return nullopt;

        return Value( type, static_pointer_cast< cir::Instruction >( ptr< void >( *cir ) ), static_cast< uint32_t >( locationId ) );
    }

    Term ValueToEIR( const ValuePattern& v )
    {
        return VEC( TSID( value ), v.sort(), v.type(), v.val(), static_cast< LocationId >( v.locationId() ) );
    }

    optional< ValuePattern > ValuePatternFromIRExpr( const Term& t )
    {
        auto result = Decompose( t,
Changes to bs/eir/value.h.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace goose::eir
{
    class Value;
    class ValuePattern;

    extern const Term& TypeType();

    extern Term ValueToIRExpr( const Value& v );
    extern optional< Value > ValueFromIRExpr( const Term& t );

    extern Term ValueToIRExpr( const ValuePattern& v );
    extern optional< ValuePattern > ValuePatternFromIRExpr( const Term& t );

    class Value
    {
        public:
            Value() : m_locationId( ~0 ) {}








|
|

|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace goose::eir
{
    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 > ValuePatternFromIRExpr( const Term& t );

    class Value
    {
        public:
            Value() : m_locationId( ~0 ) {}

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
            auto&& setPoison() { m_locationId = ~0; return *this; }

            bool isConstant() const { return holds_alternative< Term >( m_valOrCIR ); }
            bool isType() const;

            friend ostream& operator<<( ostream& out, const Value& val )
            {
                return out << ValueToIRExpr( val );
            }

            bool operator==( const Value& rhs ) const
            {
                return m_type == rhs.m_type && m_valOrCIR == rhs.m_valOrCIR;
            }








|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
            auto&& setPoison() { m_locationId = ~0; return *this; }

            bool isConstant() const { return holds_alternative< Term >( m_valOrCIR ); }
            bool isType() const;

            friend ostream& operator<<( ostream& out, const Value& val )
            {
                return out << ValueToEIR( val );
            }

            bool operator==( const Value& rhs ) const
            {
                return m_type == rhs.m_type && m_valOrCIR == rhs.m_valOrCIR;
            }

Changes to bs/execute/eval.cpp.
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

            ForEachInTuple( v, [&]( auto&& v )
            {
                auto newV = Evaluate( v, vm );
                if( newV.isPoison() )
                    poison = true;

                vals.append( ValueToIRExpr( move( newV ) ) );
                return true;
            } );

            Value newTup( v.type(), make_shared< Vector >( move( vals ) ) );
            if( poison )
                newTup.setPoison();








|







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

            ForEachInTuple( v, [&]( auto&& v )
            {
                auto newV = Evaluate( v, vm );
                if( newV.isPoison() )
                    poison = true;

                vals.append( ValueToEIR( move( newV ) ) );
                return true;
            } );

            Value newTup( v.type(), make_shared< Vector >( move( vals ) ) );
            if( poison )
                newTup.setPoison();

Changes to bs/execute/vm.cpp.
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
    bool poisoned = false;
    const auto& vec = *get< pvec >( call.args() );

    if( IsBuiltinFunc( func ) )
    {
        auto newVec = vec.transform( [&]( auto&& x ) -> optional< Term >
        {
            auto val = ValueFromIRExpr( x );
            assert( val );

            auto newVal = Evaluate( *val, *this );
            if( newVal.isPoison() )
                poisoned = true;

            if( !newVal.isConstant() )
            {
                poisoned = true;
                return ValueToIRExpr( PoisonValue() );
            }

            return ValueToIRExpr( newVal );
        } );

        if( poisoned )
            return PoisonValue();

        if( !newVec )
            return nullopt;

        return ExecuteBuiltinFuncCall( func, TERM( newVec ) );
    }

    const auto* pFunc = GetFuncCIR( func );

    if( !pFunc || !pFunc->isValid() )
        return PoisonValue();

    auto savedStackSize = m_stack.size();

    for( auto&& a : vec.terms() )
    {
        auto val = ValueFromIRExpr( a );
        assert( val );

        auto newVal = Evaluate( *val, *this );
        if( newVal.isPoison()  )
        {
            m_stack.resize( savedStackSize );
            return PoisonValue();
        }

        if( !newVal.isConstant() )
        {
            m_stack.resize( savedStackSize );
            return nullopt;
        }

        m_stack.emplace_back( ValueToIRExpr( newVal ) );
    }

    swap( m_currentFrameStart, savedStackSize );
    auto result = execute( *pFunc->body() );
    swap( m_currentFrameStart, savedStackSize );

    m_stack.resize( savedStackSize );







|









|


|




















|















|







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
    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() )
            {
                poisoned = true;
                return ValueToEIR( PoisonValue() );
            }

            return ValueToEIR( newVal );
        } );

        if( poisoned )
            return PoisonValue();

        if( !newVec )
            return nullopt;

        return ExecuteBuiltinFuncCall( func, TERM( newVec ) );
    }

    const auto* pFunc = GetFuncCIR( func );

    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();
        }

        if( !newVal.isConstant() )
        {
            m_stack.resize( savedStackSize );
            return nullopt;
        }

        m_stack.emplace_back( ValueToEIR( newVal ) );
    }

    swap( m_currentFrameStart, savedStackSize );
    auto result = execute( *pFunc->body() );
    swap( m_currentFrameStart, savedStackSize );

    m_stack.resize( savedStackSize );
158
159
160
161
162
163
164
165
166
167
168
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

optional< Value > VM::execute( const cir::CreateTemporary& ct )
{
    auto stackIndex = m_currentFrameStart + ct.index();
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    m_stack[stackIndex] = ValueToIRExpr( Evaluate( ct.value(), *this ) );
    return nullopt;
}

optional< Value > VM::execute( const cir::GetTemporary& gt )
{
    auto stackIndex = gt.index() + m_currentFrameStart;
    if( stackIndex >= m_stack.size() )
        return PoisonValue();

    return ValueFromIRExpr( m_stack[stackIndex] );
}

optional< Value > VM::execute( const cir::AllocVar& av )
{
    auto stackIndex = m_currentFrameStart + av.index();

    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    m_stack[stackIndex] = BuildUninitializedValue( av.type() );
    return nullopt;
}

optional< Value > VM::execute( const cir::Load& l )
{
    auto addrInt = FromValue< uintptr_t >( Evaluate( l.addr(), *this ) );
    if( !addrInt )
        return nullopt;

    auto addr = reinterpret_cast< const Term* >( *addrInt );
    return ValueFromIRExpr( *addr );
}

optional< Value > VM::execute( const cir::Store& s )
{
    auto addrInt = FromValue< uintptr_t >( Evaluate( s.addr(), *this ) );
    if( !addrInt )
        return nullopt;

    auto addr = reinterpret_cast< Term* >( *addrInt );

    auto result = Evaluate( s.val(), *this );
    if( !result.isConstant() )
        return PoisonValue();

    *addr = ValueToIRExpr( result );
    return nullopt;
}

optional< Value > VM::execute( const cir::Phi& p )
{
    auto stackIndex = m_currentFrameStart + p.destIndex();
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    p.forAllIncomings( [&]( auto&& bb, auto&& val )
    {
        if( bb == m_pPreviousBB )
        {
            m_stack[stackIndex] = ValueToIRExpr( Evaluate( val, *this ) );
            return false;
        }

        return true;
    } );

    return PoisonValue();







|









|




















|














|













|







158
159
160
161
162
163
164
165
166
167
168
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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232

optional< Value > VM::execute( const cir::CreateTemporary& ct )
{
    auto stackIndex = m_currentFrameStart + ct.index();
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    m_stack[stackIndex] = ValueToEIR( Evaluate( ct.value(), *this ) );
    return nullopt;
}

optional< Value > VM::execute( const cir::GetTemporary& gt )
{
    auto stackIndex = gt.index() + m_currentFrameStart;
    if( stackIndex >= m_stack.size() )
        return PoisonValue();

    return ValueFromEIR( m_stack[stackIndex] );
}

optional< Value > VM::execute( const cir::AllocVar& av )
{
    auto stackIndex = m_currentFrameStart + av.index();

    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    m_stack[stackIndex] = BuildUninitializedValue( av.type() );
    return nullopt;
}

optional< Value > VM::execute( const cir::Load& l )
{
    auto addrInt = FromValue< uintptr_t >( Evaluate( l.addr(), *this ) );
    if( !addrInt )
        return nullopt;

    auto addr = reinterpret_cast< const Term* >( *addrInt );
    return ValueFromEIR( *addr );
}

optional< Value > VM::execute( const cir::Store& s )
{
    auto addrInt = FromValue< uintptr_t >( Evaluate( s.addr(), *this ) );
    if( !addrInt )
        return nullopt;

    auto addr = reinterpret_cast< Term* >( *addrInt );

    auto result = Evaluate( s.val(), *this );
    if( !result.isConstant() )
        return PoisonValue();

    *addr = ValueToEIR( result );
    return nullopt;
}

optional< Value > VM::execute( const cir::Phi& p )
{
    auto stackIndex = m_currentFrameStart + p.destIndex();
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    p.forAllIncomings( [&]( auto&& bb, auto&& val )
    {
        if( bb == m_pPreviousBB )
        {
            m_stack[stackIndex] = ValueToEIR( Evaluate( val, *this ) );
            return false;
        }

        return true;
    } );

    return PoisonValue();
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
{
    auto* pTerm = calcAddress( addr.baseAddr() );
    if( !pTerm )
        return nullptr;

    for( auto&& index : addr.path() )
    {
        auto val = *ValueFromIRExpr( *pTerm );

        // We only support tuples now, we'll also support arrays in the future.
        // Everything else (structs, classes, containers, etc.) should build on top
        // of those two fundamental types.
        if( !IsTuple( val ) )
            return nullptr;








|







314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
{
    auto* pTerm = calcAddress( addr.baseAddr() );
    if( !pTerm )
        return nullptr;

    for( auto&& index : addr.path() )
    {
        auto val = *ValueFromEIR( *pTerm );

        // We only support tuples now, we'll also support arrays in the future.
        // Everything else (structs, classes, containers, etc.) should build on top
        // of those two fundamental types.
        if( !IsTuple( val ) )
            return nullptr;

348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    if( stackIndex >= m_stack.size() )
        return nullptr;

    if( m_stack[stackIndex] == TSID( UNINITIALIZED ) )
        m_stack[stackIndex] = ValueToIRExpr( Evaluate( ta.m_initValue, *this ) );

    return &m_stack[stackIndex];
}

Term* VM::calcAddress( const cir::VarBaseAddr& va )
{
    auto stackIndex = m_currentFrameStart + va.index;







|







348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
    if( m_stack.size() <= stackIndex )
        m_stack.resize( stackIndex + 1, TSID( UNINITIALIZED ) );

    if( stackIndex >= m_stack.size() )
        return nullptr;

    if( m_stack[stackIndex] == TSID( UNINITIALIZED ) )
        m_stack[stackIndex] = ValueToEIR( Evaluate( ta.m_initValue, *this ) );

    return &m_stack[stackIndex];
}

Term* VM::calcAddress( const cir::VarBaseAddr& va )
{
    auto stackIndex = m_currentFrameStart + va.index;
372
373
374
375
376
377
378
379
380
381
382
383
384
        return TSID( UNINITIALIZED );

    auto tupContent = make_shared< Vector >();
    tupContent->reserve( TupleTypeSize( type ) );

    ForEachInTupleType( type, [&]( auto&& t )
    {
        tupContent->append( BuildUninitializedValue( *ValueFromIRExpr( t ) ) );
        return true;
    } );

    return ValueToIRExpr( Value( ValueToIRExpr( type ), TERM( move( tupContent ) ) ) );
}







|



|

372
373
374
375
376
377
378
379
380
381
382
383
384
        return TSID( UNINITIALIZED );

    auto tupContent = make_shared< Vector >();
    tupContent->reserve( TupleTypeSize( type ) );

    ForEachInTupleType( type, [&]( auto&& t )
    {
        tupContent->append( BuildUninitializedValue( *ValueFromEIR( t ) ) );
        return true;
    } );

    return ValueToEIR( Value( ValueToEIR( type ), TERM( move( tupContent ) ) ) );
}
Changes to bs/parse/func.cpp.
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
    return true;
}

bool Parser::parseFunctionDeclaration( const Value& decl, const Value& paramsDecl )
{
    auto d = FromValue< Decl >( decl );

    if( !parseFuncType( *ValueFromIRExpr( d->type() ), paramsDecl ) )
        return false;

    const auto& c = context();

    auto funcIdentity = DuplicateVectorTerm( c.identity() );
    get< pvec >( funcIdentity )->terms().back() = TERM( d->name() );

    auto func = parseFunctionDeclaration( funcIdentity, paramsDecl );
    if( !func )
        return false;

    // If we're here, this is not an overload, but the first time we come accross this function.
    // So create a new overload set. The case of actually overloading an existing function is parsed
    // elsewhere.
    auto pOvlSet = make_shared< OverloadSet >( funcIdentity );
    pOvlSet->add( *c.env(), *func );

    c.env()->storeValue( funcIdentity, ANYTERM( _ ),
        ValueToIRExpr( ToValue( pOvlSet ) ) );

    return true;
}

optional< Value > Parser::parseFunctionDeclaration( const Term& identity, const Value& paramsDecl )
{
    if( !peekLastValue() )







|


















|







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
    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 = DuplicateVectorTerm( c.identity() );
    get< pvec >( funcIdentity )->terms().back() = TERM( d->name() );

    auto func = parseFunctionDeclaration( funcIdentity, paramsDecl );
    if( !func )
        return false;

    // If we're here, this is not an overload, but the first time we come accross this function.
    // So create a new overload set. The case of actually overloading an existing function is parsed
    // elsewhere.
    auto pOvlSet = make_shared< OverloadSet >( funcIdentity );
    pOvlSet->add( *c.env(), *func );

    c.env()->storeValue( funcIdentity, ANYTERM( _ ),
        ValueToEIR( ToValue( pOvlSet ) ) );

    return true;
}

optional< Value > Parser::parseFunctionDeclaration( const Term& identity, const Value& paramsDecl )
{
    if( !peekLastValue() )
Changes to bs/parse/parser.cpp.
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

    // If the identifier is preceded by a TExpr or a Type,
    // then this becomes a TDecl or a Decl, respectively.
    if( IsTExpr( *leftVal ) )
    {
        auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );

        auto texpr = ValueToIRExpr( *popType() );
        pushValue( ToValue( TNamedDecl( move( texpr ), *name ) ).setLocationId( loc ) );
        return true;
    }
    else if( IsType( *leftVal ) )
    {
        auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );

        auto type = ValueToIRExpr( *popType() );
        pushValue( ToValue( Decl( move( type ), *name ) ).setLocationId( loc ) );
        return true;
    }

    return parsePrefix( strid, prec );
}

bool Parser::parsePrefix( const pvec& vec, uint32_t prec )
{
    auto t = *m_resolver->lookAhead();

    auto val = ValueFromIRExpr( 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.







|







|











|







209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243

    // If the identifier is preceded by a TExpr or a Type,
    // then this becomes a TDecl or a Decl, respectively.
    if( IsTExpr( *leftVal ) )
    {
        auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );

        auto texpr = ValueToEIR( *popType() );
        pushValue( ToValue( TNamedDecl( move( texpr ), *name ) ).setLocationId( loc ) );
        return true;
    }
    else if( IsType( *leftVal ) )
    {
        auto loc = Location::CreateSpanningLocation( leftVal->locationId(), nameTerm->second );

        auto type = ValueToEIR( *popType() );
        pushValue( ToValue( Decl( move( type ), *name ) ).setLocationId( loc ) );
        return true;
    }

    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.
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 = ValueFromIRExpr( 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 = ValueFromEIR( 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 = ValueFromIRExpr( 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 = ValueFromEIR( t.first );
    if( !val )
        return false;

    if( val->isPoison() )
        DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::Silent );

    if( val->type() == GetValueType< ptr< OverloadSet > >() )
Changes to bs/parse/rule-helpers.cpp.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "parse.h"

using namespace goose;
using namespace goose::parse;

namespace goose::eir
{
    const Term& Bridge< parse::Rule >::Type()
    {
        static auto type = ValueToIRExpr( Value( TypeType(), VEC( TSID( ct_type ), TSID( rule ) ) ) );
        return type;
    }

    Value Bridge< parse::Rule >::ToValue( parse::Rule&& r )
    {
        ptr< void > prule = make_shared< parse::Rule >( move( r ) );
        return Value( Type(), TERM( move( prule ) ) );









|







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

using namespace goose;
using namespace goose::parse;

namespace goose::eir
{
    const Term& Bridge< parse::Rule >::Type()
    {
        static auto type = ValueToEIR( Value( TypeType(), VEC( TSID( ct_type ), TSID( rule ) ) ) );
        return type;
    }

    Value Bridge< parse::Rule >::ToValue( parse::Rule&& r )
    {
        ptr< void > prule = make_shared< parse::Rule >( move( r ) );
        return Value( Type(), TERM( move( prule ) ) );
28
29
30
31
32
33
34
35
36
37
38
}

namespace goose::parse
{
    void RegisterRule( sema::Env& env, const Term& identity, Rule&& rule )
    {
        auto ruleVal = ToValue( move( rule ) );
        auto ruleTerm = ValueToIRExpr( ruleVal );
        env.storeValue( identity, ANYTERM( _ ), ruleTerm );
    }
}







|



28
29
30
31
32
33
34
35
36
37
38
}

namespace goose::parse
{
    void RegisterRule( sema::Env& env, const Term& identity, Rule&& rule )
    {
        auto ruleVal = ToValue( move( rule ) );
        auto ruleTerm = ValueToEIR( ruleVal );
        env.storeValue( identity, ANYTERM( _ ), ruleTerm );
    }
}
Changes to bs/parse/tfunc.cpp.
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
    return true;
}

bool Parser::parseTemplateFunctionTNamedDecl( const Value& tnamedDecl, const Value& paramsDecl )
{
    auto d = FromValue< TNamedDecl >( tnamedDecl );

    if( !parseTFuncType( *ValueFromIRExpr( d->type() ), paramsDecl ) )
        return false;

    const auto& c = context();

    auto tfuncIdentity = DuplicateVectorTerm( c.identity() );
    get< pvec >( tfuncIdentity )->terms().back() = TERM( d->name() );

    auto tfunc = parseTemplateFunction( tfuncIdentity, paramsDecl );
    if( tfunc.isPoison() )
        return true;

    // If we're here, this is not an overload, but the first time we come accross this function.
    // So create a new overload set. The case of actually overloading an existing function is parsed
    // elsewhere.
    auto pOvlSet = make_shared< OverloadSet >( tfuncIdentity );
    pOvlSet->add( *c.env(), tfunc );

    c.env()->storeValue( tfuncIdentity, ANYTERM( _ ),
        ValueToIRExpr( ToValue( pOvlSet ) ) );

    return true;
}

Value Parser::parseTemplateFunction( const Term& identity, const Value& paramsDecl )
{
    auto pBody = getFuncBody();







|


















|







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
    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 = DuplicateVectorTerm( c.identity() );
    get< pvec >( tfuncIdentity )->terms().back() = TERM( d->name() );

    auto tfunc = parseTemplateFunction( tfuncIdentity, paramsDecl );
    if( tfunc.isPoison() )
        return true;

    // If we're here, this is not an overload, but the first time we come accross this function.
    // So create a new overload set. The case of actually overloading an existing function is parsed
    // elsewhere.
    auto pOvlSet = make_shared< OverloadSet >( tfuncIdentity );
    pOvlSet->add( *c.env(), tfunc );

    c.env()->storeValue( tfuncIdentity, ANYTERM( _ ),
        ValueToEIR( ToValue( pOvlSet ) ) );

    return true;
}

Value Parser::parseTemplateFunction( const Term& identity, const Value& paramsDecl )
{
    auto pBody = getFuncBody();
Changes to bs/sema/invocation.cpp.
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    {
        const auto& rules = e.invocationRuleSet()->rules();

        MatchSolution bestSol;
        ptr< InvocationRule > pBestRule;
        bool ambiguous = false;

        auto calleeTerm = ValueToIRExpr( callee );

        for( auto&& [s, rule] : Match( calleeTerm, rules ) )
        {
            if( !pBestRule || s > bestSol )
            {
                bestSol = s;
                pBestRule = rule;







|







8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    {
        const auto& rules = e.invocationRuleSet()->rules();

        MatchSolution bestSol;
        ptr< InvocationRule > pBestRule;
        bool ambiguous = false;

        auto calleeTerm = ValueToEIR( callee );

        for( auto&& [s, rule] : Match( calleeTerm, rules ) )
        {
            if( !pBestRule || s > bestSol )
            {
                bestSol = s;
                pBestRule = rule;
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( *ValueFromIRExpr( 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( *ValueFromIRExpr( 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( *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 )
    {
Changes to bs/sema/template.cpp.
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

    optional< Term > BuildTemplateSignature( const Context& c, const Term& tpl )
    {
        const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
        if( !pTemplateRuleSet )
            return nullopt;

        return pTemplateRuleSet->buildSignature( c, *ValueFromIRExpr( tpl ) );
    }

    Value BuildTemplateParam( const Context& c, const Term& tpl, const Term& arg )
    {
        const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
        if( !pTemplateRuleSet )
            return PoisonValue();

        return pTemplateRuleSet->buildParamDecl( c, *ValueFromIRExpr( tpl ), *ValueFromIRExpr( arg ) );
    }

    void TemplateSetup( const Context& c, TypeCheckingContext tcc, const Term& tpl )
    {
        const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
        if( !pTemplateRuleSet )
            return;

        pTemplateRuleSet->setup( c, tcc, *ValueFromIRExpr( tpl ) );
    }

    extern optional< Term > BuildTemplateArgPattern( const Context& c, const Term& tpl )
    {
        const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
        if( !pTemplateRuleSet )
            return nullopt;

        return pTemplateRuleSet->buildArgPattern( c, *ValueFromIRExpr( tpl ) );
    }
}







|








|








|








|


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

    optional< Term > BuildTemplateSignature( const Context& c, const Term& tpl )
    {
        const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
        if( !pTemplateRuleSet )
            return nullopt;

        return pTemplateRuleSet->buildSignature( c, *ValueFromEIR( tpl ) );
    }

    Value BuildTemplateParam( const Context& c, const Term& tpl, const Term& arg )
    {
        const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
        if( !pTemplateRuleSet )
            return PoisonValue();

        return pTemplateRuleSet->buildParamDecl( c, *ValueFromEIR( tpl ), *ValueFromEIR( arg ) );
    }

    void TemplateSetup( const Context& c, TypeCheckingContext tcc, const Term& tpl )
    {
        const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
        if( !pTemplateRuleSet )
            return;

        pTemplateRuleSet->setup( c, tcc, *ValueFromEIR( tpl ) );
    }

    extern optional< Term > BuildTemplateArgPattern( const Context& c, const Term& tpl )
    {
        const auto pTemplateRuleSet = GetTemplateRuleSet( c, tpl );
        if( !pTemplateRuleSet )
            return nullopt;

        return pTemplateRuleSet->buildArgPattern( c, *ValueFromEIR( tpl ) );
    }
}
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 = *ValueFromIRExpr( 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 = *ValueFromEIR( 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 = *ValueFromIRExpr( 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, *ValueFromIRExpr( 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 = *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;
    }
}
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 = ValueFromIRExpr( 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 = ValueFromEIR( t );

            if( !arg->isConstant() )
            {
                execute::VM vm;
                arg = execute::Evaluate( *arg, vm );

                if( !arg->isConstant() )
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
            return true;
        } );

        // Check preconditions.
        const auto& preConds = fvi->preConditions();
        ForEachInVectorTerm( preConds, [&]( auto&& t )
        {
            auto val = *ValueFromIRExpr( 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();
    }
}







|













159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
            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();
    }
}
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 = *ValueFromIRExpr( 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 = *ValueFromEIR( t );
        if( val.isPoison() )
        {
            success = false;
            return false;
        }

        if( val.type() != GetValueType< bool >() )
Changes to bs/verify/func.cpp.
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

                // 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, *ValueFromIRExpr( t ) ) )
                        m_builder.assume( zv->expr );

                    return true;
                } );
            }

            bool result = buildZ3Expressions( *m_cfg->entryBB(), nullptr );







|







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107

                // 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 );
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 = *ValueFromIRExpr( 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 = *ValueFromIRExpr( 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 = *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 )
Changes to bs/verify/storage.cpp.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    {
        auto val = LoadFromAddress( b, addr.baseAddr() );
        if( !val )
            return nullopt;

        for( auto&& index : addr.path() )
        {
            auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToIRExpr( val->type ) );
            if( !tinfo )
                return nullopt;

            // The only aggregate type that we handle for now are tuples.
            // TODO: arrays
            auto elemType = GetTupleTypeElement( val->type, index );
            auto elemExpr = tinfo->proj( val->expr, index );
            val = Z3Val{ move( elemExpr ), *ValueFromIRExpr( elemType ) };
        }

        return val;
    }

    optional< Z3Val > LoadFromAddress( Builder& b, const BaseAddress& baseAddr )
    {







|







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
    {
        auto val = LoadFromAddress( b, addr.baseAddr() );
        if( !val )
            return nullopt;

        for( auto&& index : addr.path() )
        {
            auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( val->type ) );
            if( !tinfo )
                return nullopt;

            // The only aggregate type that we handle for now are tuples.
            // TODO: arrays
            auto elemType = GetTupleTypeElement( val->type, index );
            auto elemExpr = tinfo->proj( val->expr, index );
            val = Z3Val{ move( elemExpr ), *ValueFromEIR( elemType ) };
        }

        return val;
    }

    optional< Z3Val > LoadFromAddress( Builder& b, const BaseAddress& baseAddr )
    {
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    optional< Z3Val > LoadFromAddress( Builder& b, const cir::VarBaseAddr& va )
    {
        return b.retrieveVar( va.index );
    }

    optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const AddressPath& path, uint32_t index, Z3Val&& valToStore )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToIRExpr( aggregate.type ) );
        if( !tinfo )
            return nullopt;

        // The only aggregate type that we handle for now are tuples.
        // TODO: arrays
        auto elemCount = TupleTypeSize( aggregate.type );








|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    optional< Z3Val > LoadFromAddress( Builder& b, const cir::VarBaseAddr& va )
    {
        return b.retrieveVar( va.index );
    }

    optional< z3::expr > ModifyAggregate( Builder& b, const Z3Val& aggregate, const AddressPath& path, uint32_t index, Z3Val&& valToStore )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( aggregate.type ) );
        if( !tinfo )
            return nullopt;

        // The only aggregate type that we handle for now are tuples.
        // TODO: arrays
        auto elemCount = TupleTypeSize( aggregate.type );

75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
            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 < ( path.size() - 1 ) )
                {
                    auto newElem = ModifyAggregate( b, Z3Val{ move( elemExpr ), *ValueFromIRExpr( elemType ) }, path, ++index, move( valToStore ) );
                    if( !newElem )
                        return nullopt;

                    args.push_back( move( *newElem ) );
                }
                else
                    args.push_back( valToStore.expr );







|







75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
            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 < ( path.size() - 1 ) )
                {
                    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 );
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 = *ValueFromIRExpr( 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 = *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
Changes to bs/verify/type.cpp.
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    return tinfo;
}

optional< TypeInfo > TypeCache::CreateTypeInfoForBasicType( const sema::Context& c, const Value& typeVal )
{
    // Handle all non-aggregate types (bool, signed int, unsigned int, floats) directly.
    // TODO: some are missing and will be dealt with later on.
    if( ValueToIRExpr( typeVal ) == GetValueType< bool >() )
    {
        return TypeInfo { GetZ3Context().bool_sort(),
            []( auto&& b )
            {
                return GetZ3Context().bool_const( format( "u{}", b.newUniqueId() ).c_str() );
            },
            []( auto&& b, auto&& val )







|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
    return tinfo;
}

optional< TypeInfo > TypeCache::CreateTypeInfoForBasicType( const sema::Context& c, const Value& typeVal )
{
    // Handle all non-aggregate types (bool, signed int, unsigned int, floats) directly.
    // TODO: some are missing and will be dealt with later on.
    if( ValueToEIR( typeVal ) == GetValueType< bool >() )
    {
        return TypeInfo { GetZ3Context().bool_sort(),
            []( auto&& b )
            {
                return GetZ3Context().bool_const( format( "u{}", b.newUniqueId() ).c_str() );
            },
            []( auto&& b, auto&& val )
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    }

    return nullopt;
}

optional< TypeInfo > TypeCache::CreateTypeInfo( const sema::Context& c, const Term& type )
{
    auto typeVal = *ValueFromIRExpr( 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







|







95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
    }

    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
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 ), *ValueFromIRExpr( val.type() ) };
    }

    optional< Z3Val > BuildZ3ConstantFromType( Builder& b, const Value& type, const string& name )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToIRExpr( 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 ), *ValueFromIRExpr( 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 ), *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;

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 ), *ValueFromIRExpr( 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 ), *ValueFromIRExpr( GetValueType< bool >() ) };
        }
        else
        {
            assert( lhs->expr.is_int() );
            return Z3Val{ func( GetAsBitVec( *lhs ), rhs->expr, lhs->type ), *ValueFromIRExpr( 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 ), *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 )
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
            return zv;

        return BuildZ3ConstantFromType( b, instr.type(), format( "v{}", instr.index() ) );
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const AllocVar& instr )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToIRExpr( instr.type() ) );
        if( !tinfo )
            return nullopt;

        b.setVar( instr.index(), Z3Val{ tinfo->undefined( b ), instr.type() } );
        return nullopt;
    }








|







180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
            return zv;

        return BuildZ3ConstantFromType( b, instr.type(), format( "v{}", instr.index() ) );
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const AllocVar& instr )
    {
        auto tinfo = TypeCache::GetInstance()->getTypeInfo( b.context(), ValueToEIR( instr.type() ) );
        if( !tinfo )
            return nullopt;

        b.setVar( instr.index(), Z3Val{ tinfo->undefined( b ), instr.type() } );
        return nullopt;
    }

378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
        return nullopt;
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const Placeholder& instr )
    {
        const auto* expr = b.retrievePlaceholder( instr.name() );
        if( expr )
            return Z3Val{ *expr, *ValueFromIRExpr( instr.type() ) };

        return BuildZ3ConstantFromType( b, instr.type(), format( "p{}", instr.name() ) );
    }

    optional< Z3Val > BuildZ3Op( Builder& b, const cir::Instruction& instr )
    {
        return visit( [&]( auto&& e )







|







378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
        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 )