Goose  Check-in [7b9f645074]

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

Overview
Comment:Removed the vector "typechecking rule", whose existence made no sense. Typechecking rules should operate only on values and pattern of values. Typechecking multiple values against multiple params is now done through a specific function instead.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 7b9f645074e65ff800e2d54fadb6f35df62c032a5d448adb73277a437ee9c574
User & Date: achavasse 2021-01-21 21:05:48.734
Context
2021-02-01
12:56
Correctly handle references to references, plus some code cleaning. check-in: ba909d1a94 user: achavasse tags: trunk
2021-01-21
21:05
Removed the vector "typechecking rule", whose existence made no sense. Typechecking rules should operate only on values and pattern of values. Typechecking multiple values against multiple params is now done through a specific function instead. check-in: 7b9f645074 user: achavasse tags: trunk
2021-01-13
11:46
Sema: simplification: the "half-unification" rules don't need to be generators, they can only output one result. check-in: 3bf30e74ac user: achavasse tags: trunk
Changes
Side-by-Side Diff Ignore Whitespace Patch
Changes to bs/builtins/types/constrainedfunc/invoke.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
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::sema;

namespace goose::builtins
{
    class ConstrainedFuncInvocationRule : public InvocationRule
    {
        public:
            Value resolveInvocation( const Context& c, uint32_t loc, const Value& callee, const Term& args ) const final
            {
                auto callPat = VEC( args, HOLE( "_"_sid ) );
                auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid ) );

                // Unify with the constraint pattern. We only care that there is at least one
                // solution, and if so, we defer the actual call resolution to the contained
                // function.
                auto cfunc = FromValue< ConstrainedFunc >( callee );
                assert( cfunc );

                TypeCheckingContext tcc( c );
                tcc.setComplexity( GetComplexity( cfunc->constraintPat() ) + GetComplexity( callPat ) );

                for( auto&& [s, tcc] : TypeCheck( cfunc->constraintPat(), callPat, tcc ) )
                for( auto&& [s, tcc] : TypeCheckVec( cfunc->constraintPat(), callPat, tcc ) )
                {
                    if( Postprocess( s, tcc ) )
                        return cfunc->invRule()->resolveInvocation( c, loc, cfunc->func(), args );
                }

                // TODO display details
                DiagnosticsManager::GetInstance().emitErrorMessage( loc,
Changes to bs/builtins/types/constrainedfunc/typecheck.cpp.
40
41
42
43
44
45
46
47

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

47
48
49
50
51
52
53
54







-
+







            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 ) )
            for( auto&& [s, tcc] : TypeCheckVec( callPat, cfunc->constraintPat(), localC ) )
            {
                if( Postprocess( s, tcc ) )
                {
                    auto func = ValueToEIR( cfunc->func() );
                    co_yield TypeCheck( lhs, func, tcc );
                    co_return;
                }
Changes to bs/builtins/types/func/build.cpp.
83
84
85
86
87
88
89
90


91
92
93
94
95
96
97
83
84
85
86
87
88
89

90
91
92
93
94
95
96
97
98







-
+
+







    }

    Term BuildCallPatternFromFuncType( const Value& funcType )
    {
        auto ftype = *FromValue< FuncType >( funcType );

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

        ForEachInVectorTerm( ftype.params(), [&]( auto&& param )
        {
            auto result = Decompose( param,
                Vec(
                    Lit( "value"_sid ),
                    SubTerm(),
108
109
110
111
112
113
114
115

116
117
109
110
111
112
113
114
115

116
117
118







-
+


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

            return true;
        } );

        return VEC( apv, ftype.returnType() );
        return TERM( apv );
    }
}
Changes to bs/builtins/types/func/func.cpp.
66
67
68
69
70
71
72
73

74
75
76
77
78
79
80
66
67
68
69
70
71
72

73
74
75
76
77
78
79
80







-
+







                SubTerm(),  // verif infos
                SubTerm()   // VarArg
            )
        );
        assert( typeDecomp );
        auto&& [kind, rtype, ptypes, vinf, varArg] = *typeDecomp;

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

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

Changes to bs/builtins/types/func/invoke.cpp.
10
11
12
13
14
15
16
17

18
19

20
21
22
23
24
25
26
10
11
12
13
14
15
16

17
18

19
20
21
22
23
24
25
26







-
+

-
+







            Value resolveInvocation( const Context& c, uint32_t loc, const Value& callee, const Term& args ) const final
            {
                optional< TypeCheckingContext > bestTCC;
                optional< Term > bestSol;
                bool ambiguous = false;

                auto sig = GetFuncSig( callee );
                auto callPat = VEC( args, HOLE( "_"_sid ) );
                auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid ) );

                auto us = FindBestTyping( sig, callPat, c );
                auto us = FindBestTypingVec( sig, callPat, c );

                if( holds_alternative< NoUnification >( us ) )
                {
                    // TODO display details
                    DiagnosticsManager::GetInstance().emitErrorMessage( loc,
                        "function arguments mismatch." );
                    return PoisonValue();
42
43
44
45
46
47
48
49

50
51
52
53
54

55

56
57
58
59
60
61
62
42
43
44
45
46
47
48

49



50
51
52

53
54
55
56
57
58
59
60







-
+
-
-
-


+
-
+







            Value invoke( const Context& c, uint32_t loc, const Value& callee, const Term& args, const Term& unifiedCallPat, TypeCheckingContext& tcc ) const final
            {
                auto newCallee = prepareFunc( c, 0, callee, unifiedCallPat, tcc );
                if( newCallee.isPoison() )
                    return PoisonValue();

                auto callDecomp = Decompose( unifiedCallPat,
                    Vec(
                    Val< pvec >()
                        SubTerm(),  // args
                        SubTerm()   // return type
                    )
                );

                const auto& unifiedRType = callDecomp->get()->terms().front();
                auto&& [unifiedArgs, unifiedRType] = *callDecomp;
                auto unifiedArgs = DropVectorTerm( unifiedCallPat, 1 );

                newCallee.setLocationId( loc );

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

                if( IsIntrinsicFunc( newCallee ) )
Changes to bs/builtins/types/func/typecheck.cpp.
128
129
130
131
132
133
134
135

136
137
138
139
140
141
142
128
129
130
131
132
133
134

135
136
137
138
139
140
141
142







-
+








            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 ) )
            for( auto&& [s, tcc] : TypeCheckVec( sig, *callPat, tcc ) )
            {
                if( IsBuiltinFunc( rhsVal ) )
                {
                    co_yield { ValueToEIR( rhsVal ), tcc };
                    continue;
                }

Changes to bs/builtins/types/localvar/localvar.cpp.
124
125
126
127
128
129
130
131

132
133
134
135
136
137
138
124
125
126
127
128
129
130

131
132
133
134
135
136
137
138







-
+








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

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

        if( holds_alternative< NoUnification >( us ) )
        {
            // TODO display details
            DiagnosticsManager::GetInstance().emitErrorMessage( 0,
                "variable initialization type mismatch." );
            return PoisonValue();
Changes to bs/builtins/types/overloadset/invoke.cpp.
12
13
14
15
16
17
18
19

20
21

22
23
24
25
26
27
28
12
13
14
15
16
17
18

19
20

21
22
23
24
25
26
27
28







-
+

-
+







                auto pOvlSet = *FromValue< ptr< OverloadSet > >( callee );

                optional< TypeCheckingContext > bestTCC;
                optional< Term > bestSol;
                const OverloadSet::Overload* bestOvl = nullptr;
                bool ambiguous = false;

                auto rtPat = HOLE( "_"_sid );
                auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid ) );
                TypeCheckingContext tcc( c );
                for( auto&& [s,ovl,tcc] : pOvlSet->typeCheck( args, rtPat, tcc ) )
                for( auto&& [s,ovl,tcc] : pOvlSet->typeCheck( callPat, tcc ) )
                {
                    if( tcc.numUnknownValues() )
                       continue;

                    if( bestTCC && tcc.score() < bestTCC->score() )
                        continue;

Changes to bs/builtins/types/overloadset/typecheck.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
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







-
-
-
-
-
-
-
-
-
-











-
+







                )
            );
            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();
            auto localNSId = tcc.newNamespaceIndex();
            tcc.setRHSNamespaceIndex( localNSId );

            for( auto&& [s,ovl,tcc] : os->typeCheck( argPat, rtPat, tcc.flip() ) )
            for( auto&& [s,ovl,tcc] : os->typeCheck( callPat, tcc.flip() ) )
            {
                if( !ovl.callee )
                    continue;

                // Restore the namespace
                tcc.flip();
                tcc.setRHSNamespaceIndex( savedRHSNamespaceIndex );
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
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







-
-
-
-
-
-
-
-
-
-











-
+







            );
            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();
            auto localNSId = tcc.newNamespaceIndex();
            tcc.setRHSNamespaceIndex( localNSId );

            for( auto&& [s,ovl,tcc] : os->typeCheck( argPat, rtPat, tcc.flip() ) )
            for( auto&& [s,ovl,tcc] : os->typeCheck( *callPat, tcc.flip() ) )
            {
                if( !ovl.callee )
                    continue;

                tcc.flip();
                tcc.setRHSNamespaceIndex( savedRHSNamespaceIndex );

Changes to bs/builtins/types/template/build.cpp.
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
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










-
+
+
+
+
+
+
+
+
+
+




















-
-
-
-
-
-
+
-
-
-

















-
+
+
+
+
+
+
+
+
+
+




















-
-
-
-
-
-
-
-
+
+
+
-
-
-
        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() ) );
        v->reserve( VecSize( tft.params() ) + 1 );

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

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

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

        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 TERM( v );
        }

        return VEC( v, *rtSig );
    }

    Value BuildTFunc( const Context& c, const TFuncType& tft, const Term& identity, const Value& params, ptr< void > body )
    {
        auto sig = BuildTFuncSignature( c, tft );
        if( !sig )
            return PoisonValue();

        return ToValue( TFunc( tft, *sig, identity, body ) );
    }

    optional< Term > BuildArgPatternFromTFuncType( const Context& c, const Value& tfuncType )
    {
        const auto& ftype = FromValue< TFuncType >( tfuncType );
        assert( ftype );

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

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

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

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

        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 TERM( apv );
    }
}
        return VEC( apv,*rtArgPat );
    }
}
Changes to bs/builtins/types/template/instantiate.cpp.
8
9
10
11
12
13
14
15

16
17
18
19
20

21

22
23
24
25
26
27
28
8
9
10
11
12
13
14

15



16
17
18

19
20
21
22
23
24
25
26







-
+
-
-
-


+
-
+







{
    Value InstantiateTFunc( const Context& c, const Value& callee, const Term& unifiedCallPat, const TypeCheckingContext& tcc )
    {
        auto tf = FromValue< TFunc >( callee );
        assert( tf );

        auto callDecomp = Decompose( unifiedCallPat,
            Vec(
            Val< pvec >()
                SubTerm(),  // args
                SubTerm()   // return type
            )
        );

        const auto& unifiedRType = callDecomp->get()->terms().front();
        auto&& [unifiedArgs, unifiedRType] = *callDecomp;
        auto unifiedArgs = DropVectorTerm( unifiedCallPat, 1 );

        // Build the instance function param types
        auto instanceParams = EmptyClosedTuple();

        ForEachInVectorTerms( tf->type().params(), unifiedArgs,
            [&]( auto&& param, auto&& arg )
            {
Changes to bs/builtins/types/template/invoke.cpp.
14
15
16
17
18
19
20
21
22


23
24
25
26
27
28
29
14
15
16
17
18
19
20


21
22
23
24
25
26
27
28
29







-
-
+
+







                auto tf = FromValue< TFunc >( callee );
                assert( tf );

                optional< TypeCheckingContext > bestTCC;
                optional< Term > bestSol;
                bool ambiguous = false;

                auto callPat = VEC( args, HOLE( "_"_sid ) );
                auto us = FindBestTyping( tf->signature(), callPat, c );
                auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid ) );
                auto us = FindBestTypingVec( tf->signature(), callPat, c );

                if( holds_alternative< NoUnification >( us ) )
                {
                    // TODO display details
                    DiagnosticsManager::GetInstance().emitErrorMessage( loc,
                        "template function arguments mismatch." );
                    return PoisonValue();
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
25
26
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









-
+








-
+







#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 )
    TCGen TypeCheckTDecl( const Term& lhs, const Term& rhs, TypeCheckingContext tcc )
    {
        auto tdecl = FromValue< TDecl >( *ValueFromEIR( lhs ) );
        assert( tdecl );

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

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

        // We are replacing lhs with a different terms and re-unifying,
        // We are replacing lhs with a different terms and typechecking again,
        // so update the complexity accordingly. The structure of the tdecl
        // shouldn't count, only its pattern.
        tcc.subComplexity( GetComplexity( lhs ) );
        tcc.addComplexity( GetComplexity( pat ) );

        for( auto&& [s,tcc] : Unify( pat, rhs, tcc ) )
        {
48
49
50
51
52
53
54
55
56


57
58
59
60
61
62
63
48
49
50
51
52
53
54


55
56
57
58
59
60
61
62
63







-
-
+
+







            []( const Term& lhs, TypeCheckingContext& c )
            {
                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 );
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, ANYTERM( _ ), TypeCheckTDecl );
        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, tDeclPat, TypeCheckTDecl );

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

99
100
101
102
103
104
105
106

107
108
109
110
111
112
113
99
100
101
102
103
104
105

106
107
108
109
110
111
112
113







-
+








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

            for( auto&& [s, tcc] : TypeCheck( callPat, rhs, tcc ) )
            for( auto&& [s, tcc] : TypeCheckVec( callPat, rhs, tcc ) )
            {
                // Restore the namespace
                tcc.setRHSNamespaceIndex( savedRHSNamespaceIndex );
                tcc.setValueResolutionRequired( oldValueRequired );

                // We need to unify the result with a hole named after the decl. However, since both sides of
                // this unification orignally appeared on the LHS, we need to setup RHS to alias the LHS namespace for this.
Changes to bs/builtins/types/template/typecheck.cpp.
44
45
46
47
48
49
50
51

52
53
54
55
56
57
58
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58







-
+








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

            for( auto&& [s, tcc] : TypeCheck( tf.signature(), callPat, tcc ) )
            for( auto&& [s, tcc] : TypeCheckVec( tf.signature(), callPat, tcc ) )
            {
                // Restore the namespace
                tcc.setRHSNamespaceIndex( savedRHSNamespaceIndex );

                auto wrapped = WrapWithPostprocFunc( s, [rhsVal,localNSId]( const Term& t, TypeCheckingContext tcc )
                    -> optional< Term >
                {
103
104
105
106
107
108
109
110

111
112
113
114
115
116
117
103
104
105
106
107
108
109

110
111
112
113
114
115
116
117







-
+








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

            for( auto&& [s, tcc] : TypeCheck( tf.signature(), *callPat,  tcc ) )
            for( auto&& [s, tcc] : TypeCheckVec( tf.signature(), *callPat,  tcc ) )
            {
                // Restore the namespace
                tcc.setRHSNamespaceIndex( savedRHSNamespaceIndex );

                auto wrapped = WrapWithPostprocFunc( s, [rhsVal,localNSId]( const Term& t, TypeCheckingContext tcc )
                    -> optional< Term >
                {
Changes to bs/sema/overloadset.cpp.
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
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







-
+
-
-
+
-
-


-
+

-
-
-
-

-
-
-
-
-
-
+
+
+
+

-
-
+
+
-





-
+

-
+



-
+


-
+

-
-
+

-
-
-
-
-
-
-
-
-
+
-
-


}

bool OverloadSet::add( const Env& e, const Value& callee, const ptr< InvocationRule >& pInvRule )
{
    auto signature = pInvRule->getSignature( callee );
    assert( signature );

    auto result = Decompose( *signature,
    auto sigDecomp = Decompose( *signature,
        Vec(
            Val< pvec >(),
        Val< pvec >()
            SubTerm()
        )
    );

    assert( result );
    assert( sigDecomp );

    auto&& [p, rt] = *result;
    const auto& rtype = rt;
    const auto& params = p;

    bool success = false;
    m_trie = m_trie->merge( *params, [&]( auto&& rtTrie )
    {
        return Merge( rtTrie, rtype, [&]( auto&& previous ) -> Overload
        {
            if( previous.callee )
                return move( previous );
    m_trie = m_trie->merge( *sigDecomp->get(), [&]( auto&& previous ) -> Overload
    {
        if( previous.callee )
            return move( previous );

            success = true;
            return { pInvRule, callee };
        success = true;
        return { pInvRule, callee };
        } );
    } );

    return success;
}

OverloadSet::TCGen OverloadSet::typeCheck( const Term& argsPat, const Term& rtPat, const TypeCheckingContext& tcc ) const
OverloadSet::TCGen OverloadSet::typeCheck( const Term& callPat, const TypeCheckingContext& tcc ) const
{
    auto argDecomp = Decompose( argsPat,
    auto callDecomp = Decompose( callPat,
        Val< pvec >()
    );

    if( !argDecomp )
    if( !callDecomp )
        co_return;

    for( auto&& [paramsVec,uniParamsVec,rtTrie,tcc] : m_trie->typeCheck( *argDecomp->get(), tcc ) )
    for( auto&& [callVec,uniCallVec,ovl,tcc] : m_trie->typeCheck( *callDecomp->get(), tcc ) )
    {
        auto params = TERM( make_shared< Vector >( paramsVec ) );
        auto uniParams = TERM( make_shared< Vector >( uniParamsVec ) );
        auto uniCall = TERM( make_shared< Vector >( uniCallVec ) );

        for( auto&& [rt,ovl] : Enumerate( rtTrie ) )
        {
            auto localC = tcc;
            localC.addComplexity( GetComplexity( rt ) + GetComplexity( rtPat ) );

            for( auto&& [uniRt,tcc] : Unify( rt, rtPat, localC ) )
            {
                auto uniCall = TERM( Vector::Make( uniParams, uniRt ) );
                co_yield { move( uniCall ), ovl, tcc };
        co_yield { move( uniCall ), ovl, tcc };
            }
        }
    }
}
Changes to bs/sema/overloadset.h.
23
24
25
26
27
28
29
30

31
32
33
34
35

36
37
38
39
40
23
24
25
26
27
28
29

30
31
32
33
34

35
36
37
38
39
40







-
+




-
+






            using TCGen = Generator< tuple<
                Term,
                const Overload&,
                TypeCheckingContext
            > >;

            TCGen typeCheck( const Term& argsPat, const Term& rtPat, const TypeCheckingContext& tcc ) const;
            TCGen typeCheck( const Term& callPat, const TypeCheckingContext& tcc ) const;

        private:
            Term m_identity;

            using trie_type = TCTrie< Trie< Overload > >;
            using trie_type = TCTrie< Overload >;
            ptr< trie_type > m_trie = make_shared< trie_type >();
    };
}

#endif
Changes to bs/sema/typecheck.cpp.
1
2
3
4

5

6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
1
2
3
4
5

6
7
8
9
10
11
12
13
14

15
16
17
18
19
20
21
22




+
-
+








-
+







#include "sema.h"

namespace goose::sema
{
    template< typename F >
    TypeCheckingSolution FindBestTyping( const Term& lhs, const Term& rhs, const Context& context )
    TypeCheckingSolution FindBestTyping( const Term& lhs, const Term& rhs, const Context& context, F&& typeChecker )
    {
        optional< TypeCheckingContext > bestTCC;
        optional< Term > bestSol;
        bool ambiguous = false;

        TypeCheckingContext tcc( context );
        tcc.setComplexity( GetComplexity( lhs ) + GetComplexity( rhs ) );

        for( auto&& [s, tcc] : TypeCheck( lhs, rhs, tcc ) )
        for( auto&& [s, tcc] : typeChecker( lhs, rhs, tcc ) )
        {
            if( tcc.numUnknownValues() )
                continue;

            if( bestTCC && tcc.score() < bestTCC->score() )
                continue;

38
39
40
41
42
43
44






45
46
47
48
49
50
51
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58







+
+
+
+
+
+







            return AmbiguousTypeCheck{};

        if( !bestSol )
            return {};

        return make_pair( move( *bestSol ), move( *bestTCC ) );
    }

    TypeCheckingSolution FindBestTyping( const Term& lhs, const Term& rhs, const Context& context )
    {
        return FindBestTyping( lhs, rhs, context,
            []( auto&& lhs, auto&& rhs, auto&& tcc ) { return TypeCheck( lhs, rhs, tcc ); } );
    }

    TCGen TypeCheck( const Term& lhs, const Term& rhs, const TypeCheckingContext& context )
    {
        const auto& rules = context.rules()->typeCheckingRules();

        MatchSolution bestSol;
        optional< TypeCheckingRuleSet::UniRule > bestRule;
148
149
150
151
152
153
154
155













































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







-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
            throw runtime_error( "ambiguous half-unification rule" );

        if( !bestRule )
            return nullopt;

        return bestRule->func( lhs, context );
    }
}

    TCGen TypeCheckVectors( const Vector::container_type< Term >& lTerms, const Vector::container_type< Term >& rTerms, size_t i,
        const Vector& solutionVec, TypeCheckingContext tcc )
    {
        assert( lTerms.size() == rTerms.size() );
        assert( i < lTerms.size() );

        for( auto&& [u,tcc] : TypeCheck( lTerms[i], rTerms[i], tcc ) )
        {
            auto vec = Vector::MakeAppend( solutionVec, move( u ) );

            if( i == ( lTerms.size() - 1 ) )
                co_yield { TERM( make_shared< Vector >( move( vec ) ) ), tcc };
            else
                co_yield TypeCheckVectors( lTerms, rTerms, i + 1, vec, tcc );
        }
    }

    TypeCheckingSolution FindBestTypingVec( const Term& lhs, const Term& rhs, const Context& context )
    {
        return FindBestTyping( lhs, rhs, context,
            []( auto&& lhs, auto&& rhs, auto&& tcc ) { return TypeCheckVec( lhs, rhs, tcc ); } );
    }

    TCGen TypeCheckVec( const Term& lhs, const Term& rhs, const TypeCheckingContext& context )
    {
        assert( holds_alternative< pvec >( lhs ) );
        assert( holds_alternative< pvec >( rhs ) );

        const auto& lVector = get< pvec >( lhs );
        const auto& rVector = get< pvec >( rhs );

        const auto& lTerms = lVector->terms();
        const auto& rTerms = rVector->terms();

        if( lTerms.empty() )
        {
            co_yield { lhs, context };
            co_return;
        }

        Vector sol;
        co_yield TypeCheckVectors( lTerms, rTerms, 0, sol, context );
    }
}
Changes to bs/sema/typecheck.h.
11
12
13
14
15
16
17

18
19
20
21

22
23
24
25
26
27
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29







+




+






    <
        NoUnification,
        AmbiguousTypeCheck,
        TCSol
    >;

    TypeCheckingSolution FindBestTyping( const Term& lhs, const Term& rhs, const Context& context );
    TypeCheckingSolution FindBestTypingVec( const Term& lhs, const Term& rhs, const Context& context );

    using TCGen = Generator< pair< Term, TypeCheckingContext > >;

    TCGen TypeCheck( const Term& lhs, const Term& rhs, const TypeCheckingContext& context );
    TCGen TypeCheckVec( const Term& lhs, const Term& rhs, const TypeCheckingContext& context );

    TCGen Unify( const Term& lhs, const Term& rhs, const TypeCheckingContext& context );
    optional< Term > HalfUnify( const Term& lhs, TypeCheckingContext& context );
}

#endif
Changes to bs/sema/uni-basicrules.cpp.
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
15
16
17
18
19
20
21

















22
23
24
25
26
27
28







-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-







            if( i == ( lTerms.size() - 1 ) )
                co_yield { TERM( make_shared< Vector >( move( vec ) ) ), tcc };
            else
                co_yield UnifyVectors( lTerms, rTerms, i + 1, vec, tcc );
        }
    }

    TCGen TypeCheckVectors( const Vector::container_type< Term >& lTerms, const Vector::container_type< Term >& rTerms, size_t i,
        const Vector& solutionVec, TypeCheckingContext tcc )
    {
        assert( lTerms.size() == rTerms.size() );
        assert( i < lTerms.size() );

        for( auto&& [u,tcc] : TypeCheck( lTerms[i], rTerms[i], tcc ) )
        {
            auto vec = Vector::MakeAppend( solutionVec, move( u ) );

            if( i == ( lTerms.size() - 1 ) )
                co_yield { TERM( make_shared< Vector >( move( vec ) ) ), tcc };
            else
                co_yield TypeCheckVectors( lTerms, rTerms, i + 1, vec, tcc );
        }
    }

    void SetupBasicUnificationRules( TypeCheckingRuleSet& ruleSet )
    {
        // Default half-unification rule
        ruleSet.addHalfUnificationRule( TCRINFOS, ANYTERM( _ ), []( const Term& lhs, TypeCheckingContext& tcc )
        {
            // NOTE: the score here is always 0 because:
            // Vectors are going to fall into the vector half-unification rule below,
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
116
117
118
119
120
121
122

123





124
























-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
                co_yield { lhs, tcc };
                co_return;
            }

            Vector sol;
            co_yield UnifyVectors( lTerms, rTerms, 0, sol, tcc );
        } );

    }
        ruleSet.addTypeCheckingRule( TCRINFOS, VECOFLENGTH( VL ), VECOFLENGTH( VL ), []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            assert( holds_alternative< pvec >( lhs ) );
            assert( holds_alternative< pvec >( rhs ) );

}
            const auto& lVector = get< pvec >( lhs );
            const auto& rVector = get< pvec >( rhs );

            const auto& lTerms = lVector->terms();
            const auto& rTerms = rVector->terms();

            if( lTerms.empty() )
            {
                co_yield { lhs, tcc };
                co_return;
            }

            Vector sol;
            co_yield TypeCheckVectors( lTerms, rTerms, 0, sol, tcc );
        } );
    }
}
Changes to tests/noprelude/codegen/bitwiseops.ll.
8
9
10
11
12
13
14
15

16
17

18
19

20
21
22
23
24
25
26
8
9
10
11
12
13
14

15
16

17
18

19
20
21
22
23
24
25
26







-
+

-
+

-
+







  %8 = alloca i16, align 2
  store i8 %0, i8* %5, align 1
  store i8 %1, i8* %6, align 1
  store i16 %2, i16* %7, align 2
  store i16 %3, i16* %8, align 2
  %9 = load i8, i8* %5, align 1
  %10 = load i8, i8* %6, align 1
  %11 = call i8 @"_2_4s2:g0s9:#0000001cs6:lomarf_2_2_5Vr_5Vo_3ti0_4s7:integerPp_2i8i0hs1:__5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4_5Vo_3ti0_4$3Pp_2i8i0_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i8i0_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4_5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4Pi0"(i8 %9, i8 %10)
  %11 = call i8 @"_2_4s2:g0s9:#0000001cs6:lomarf_3_5Vo_3ti0_4s7:integerPp_2i8i0_5Vr_5Vo_3ti0_4$3Pp_2i8i0hs1:__5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i8i0_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4_5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4Pi0"(i8 %9, i8 %10)
  %12 = load i16, i16* %8, align 2
  %13 = call i16 @"_2_4s2:g0s9:#0000001cs6:lomarf_2_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vo_3ti0_4$3Pp_2i10i1_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4Pi0"(i16 219, i16 %12)
  %13 = call i16 @"_2_4s2:g0s9:#0000001cs6:lomarf_3_5Vo_3ti0_4s7:integerPp_2i10i1_5Vr_5Vo_3ti0_4$3Pp_2i10i1hs1:__5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4Pi0"(i16 219, i16 %12)
  %14 = load i16, i16* %8, align 2
  %15 = call i16 @"_2_4s2:g0s9:#0000001cs6:lomarf_2_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vo_3ti0_4$3Pp_2i10i1_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4Pi0"(i16 %14, i16 69)
  %15 = call i16 @"_2_4s2:g0s9:#0000001cs6:lomarf_3_5Vo_3ti0_4s7:integerPp_2i10i1_5Vr_5Vo_3ti0_4$3Pp_2i10i1hs1:__5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4Pi0"(i16 %14, i16 69)
  %16 = load i8, i8* %5, align 1
  %17 = load i8, i8* %6, align 1
  %18 = xor i8 %16, %17
  %19 = load i16, i16* %7, align 2
  %20 = load i16, i16* %8, align 2
  %21 = xor i16 %19, %20
  %22 = load i16, i16* %7, align 2
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
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







-
+










-
+









  %38 = load i16, i16* %7, align 2
  %39 = shl i16 %38, 4
  %40 = load i16, i16* %7, align 2
  %41 = ashr i16 %40, 4
  ret void
}

define private i8 @"_2_4s2:g0s9:#0000001cs6:lomarf_2_2_5Vr_5Vo_3ti0_4s7:integerPp_2i8i0hs1:__5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4_5Vo_3ti0_4$3Pp_2i8i0_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i8i0_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4_5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4Pi0"(i8 %0, i8 %1) {
define private i8 @"_2_4s2:g0s9:#0000001cs6:lomarf_3_5Vo_3ti0_4s7:integerPp_2i8i0_5Vr_5Vo_3ti0_4$3Pp_2i8i0hs1:__5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i8i0_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4_5Vr_5Vo_3ti0_4$3Pp_2i8i0h$4Pi0"(i8 %0, i8 %1) {
  %3 = alloca i8, align 1
  %4 = alloca i8, align 1
  store i8 %0, i8* %3, align 1
  store i8 %1, i8* %4, align 1
  %5 = load i8, i8* %3, align 1
  %6 = load i8, i8* %4, align 1
  %7 = xor i8 %5, %6
  ret i8 %7
}

define private i16 @"_2_4s2:g0s9:#0000001cs6:lomarf_2_2_5Vr_5Vo_3ti0_4s7:integerPp_2i10i1hs1:__5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vo_3ti0_4$3Pp_2i10i1_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4Pi0"(i16 %0, i16 %1) {
define private i16 @"_2_4s2:g0s9:#0000001cs6:lomarf_3_5Vo_3ti0_4s7:integerPp_2i10i1_5Vr_5Vo_3ti0_4$3Pp_2i10i1hs1:__5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vo_3ti0_6up_5Vo_3ti0_4$3Pp_2i10i1_2q_2_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4_5Vr_5Vo_3ti0_4$3Pp_2i10i1h$4Pi0"(i16 %0, i16 %1) {
  %3 = alloca i16, align 2
  %4 = alloca i16, align 2
  store i16 %0, i16* %3, align 2
  store i16 %1, i16* %4, align 2
  %5 = load i16, i16* %3, align 2
  %6 = load i16, i16* %4, align 2
  %7 = xor i16 %5, %6
  ret i16 %7
}