Goose  Check-in [3bf30e74ac]

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

Overview
Comment:Sema: simplification: the "half-unification" rules don't need to be generators, they can only output one result.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 3bf30e74ace51ec38ac773df6d1a1b3636022447077207ce376917297e6d630a
User & Date: achavasse 2021-01-13 11:46:18.244
Context
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
2021-01-12
21:08
Implemented missing lowering of reference types to pointer types, added a bunch of runtime/compilation time reference tests. check-in: 90c951f66f user: achavasse tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to bs/builtins/types/runtime/typecheck.cpp.
14
15
16
17
18
19
20
21
22
23

24
25
26
27
28
29
30
        // 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,








|

|
>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
        // 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, TypeCheckingContext c ) -> TCGen
        {
            if( auto s = HalfUnify( lhs, c ) )
                co_yield { *s, 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,

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

            for( auto&& [s,tcc] : HalfUnify( lhsVal->type(), tcc ) )


            {
                // We need to defer the calculation of the init value until after the rest of the type checking is complete,
                // because we need to make sure that any hole present in the integer type is resolved before we can do
                // the sign/bitsize check. However, since we still need to be able to manipulate the result as a value in
                // the mean time, we construct a value with the correct (but possibly not complete yet type), and a payload
                // that contains the type + the ct_int value wrapped with a post process callback that finalizes the job.
                auto wrapped = WrapWithPostprocFunc( VEC( lhsVal->type(), rhs ),
                []( const Term& t, TypeCheckingContext tcc ) -> optional< Term >
                {
                    auto result = Decompose( t,
                        Vec(
                            SubTerm(),
                            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;

                    if( rttype->m_signed )
                    {
                        if( ct.getMinSignedBits() > rttype->m_numBits )
                            return nullopt;

                        valToLoad = ct.sext( rttype->m_numBits );
                        valToLoad.setIsSigned( true );
                    }
                    else
                    {
                        if( ct.isNegative() )
                            return nullopt;

                        if( ct.getActiveBits() > rttype->m_numBits )
                            return nullopt;

                        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(







|














|
>
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|

|

|
|

|
|

|

|
|
|
|

|
|
|
|
|
|
|

|
|

|
|
|

|
|

|
<













|

|
>







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
                ANYTERM( _ ) ) ),

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

        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            // The rhs might not be constant. It can happen even with ct_int if the rhs is a
            // fake argument pattern generated to unify a higher-order function param.
            // It means that we are unifying a function parameter against any ct_int value,
            // which we can't (because we have to know the value to safely convert it),
            // so we reject it.
            auto rhsVal = *ValueFromEIR( rhs );
            if( !rhsVal.isConstant() )
                co_return;

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

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

            // We need to defer the calculation of the init value until after the rest of the type checking is complete,
            // because we need to make sure that any hole present in the integer type is resolved before we can do
            // the sign/bitsize check. However, since we still need to be able to manipulate the result as a value in
            // the mean time, we construct a value with the correct (but possibly not complete yet type), and a payload
            // that contains the type + the ct_int value wrapped with a post process callback that finalizes the job.
            auto wrapped = WrapWithPostprocFunc( VEC( lhsVal->type(), rhs ),
            []( const Term& t, TypeCheckingContext tcc ) -> optional< Term >
            {
                auto result = Decompose( t,
                    Vec(
                        SubTerm(),
                        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;

                if( rttype->m_signed )
                {
                    if( ct.getMinSignedBits() > rttype->m_numBits )
                        return nullopt;

                    valToLoad = ct.sext( rttype->m_numBits );
                    valToLoad.setIsSigned( true );
                }
                else
                {
                    if( ct.isNegative() )
                        return nullopt;

                    if( ct.getActiveBits() > rttype->m_numBits )
                        return nullopt;

                    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, TypeCheckingContext c ) -> TCGen
        {
            if( auto s = HalfUnify( lhs, c ) )
                co_yield { *s, c };
        } );

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

            ValueToEIR( ValuePattern(
Changes to bs/builtins/types/template/tc-tdecl.cpp.
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
    }

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







|







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

    void SetupTDeclTypeChecking( Env& e )
    {
        auto tDeclPat = ValueToEIR( Value( GetValueType< TDecl >(), VEC( ANYTERM( _ ), ANYTERM( _ ) ) ) );

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

        e.typeCheckingRuleSet()->addTypeCheckingRule( TCRINFOS, tDeclPat, ANYTERM( _ ), UnifyTDecl );
Changes to bs/sema/tc-ruleset.h.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    #define TCRINFOS TCRuleInfo{}
#endif

    class TypeCheckingRuleSet
    {
        public:
            using UniFunc = function< TCGen ( const Term& lhs, const Term& rhs, const TypeCheckingContext& ) >;
            using HalfUniFunc = function< TCGen ( const Term& lhs, const TypeCheckingContext& ) >;

            struct UniRule
            {
                UniFunc func;
                TCRuleInfo infos;
            };








|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
    #define TCRINFOS TCRuleInfo{}
#endif

    class TypeCheckingRuleSet
    {
        public:
            using UniFunc = function< TCGen ( const Term& lhs, const Term& rhs, const TypeCheckingContext& ) >;
            using HalfUniFunc = function< optional< Term > ( const Term& lhs, TypeCheckingContext& ) >;

            struct UniRule
            {
                UniFunc func;
                TCRuleInfo infos;
            };

Changes to bs/sema/tctrie-typecheck.inl.
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
            for( auto&& [t, payload] : Enumerate( get< 0 >( branch )->m_trie ) )
            {
                auto newC = tcc;
                newC.addComplexity( GetComplexity( t ) );

                auto lvec = Vector::MakeAppend( lhsVec, t );

                for( auto&& [s, tcc] : sema::HalfUnify( t, newC ) )
                    co_yield HalfUnify< T >( lvec, Vector::MakeAppend( solutionVec, move( s ) ), payload, tcc );
            }
        }
        else
            co_yield { lhsVec, solutionVec, *any_cast< T >( &get< 1 >( branch ) ), tcc };
    }

    template< typename U >







|
|







91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
            for( auto&& [t, payload] : Enumerate( get< 0 >( branch )->m_trie ) )
            {
                auto newC = tcc;
                newC.addComplexity( GetComplexity( t ) );

                auto lvec = Vector::MakeAppend( lhsVec, t );

                if( auto s = sema::HalfUnify( t, newC ) )
                    co_yield HalfUnify< T >( lvec, Vector::MakeAppend( solutionVec, move( *s ) ), payload, newC );
            }
        }
        else
            co_yield { lhsVec, solutionVec, *any_cast< T >( &get< 1 >( branch ) ), tcc };
    }

    template< typename U >
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
            for( auto&& [lv, sol, pRptNode, tcc] : HalfUnify< rpt_node >( lhs, sol, branch, tcc ) )
            {
                for( auto&& [rt, payload] : Enumerate( pRptNode->m_repetition ) )
                {
                    auto newC = tcc;
                    newC.addComplexity( GetComplexity( rt ) );

                    for( auto&& [s, c] : sema::HalfUnify( rt, newC ) )
                    {
                        auto localLhsVec = lv;
                        localLhsVec.setRepetitionTerm( rt );

                        auto localSol = sol;
                        localSol.setRepetitionTerm( move( s ) );
                        co_yield { localLhsVec, localSol, payload, c };
                    }
                }
            }
        }
    }
}

#endif







|





|
|








127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
            for( auto&& [lv, sol, pRptNode, tcc] : HalfUnify< rpt_node >( lhs, sol, branch, tcc ) )
            {
                for( auto&& [rt, payload] : Enumerate( pRptNode->m_repetition ) )
                {
                    auto newC = tcc;
                    newC.addComplexity( GetComplexity( rt ) );

                    if( auto s = sema::HalfUnify( rt, newC ) )
                    {
                        auto localLhsVec = lv;
                        localLhsVec.setRepetitionTerm( rt );

                        auto localSol = sol;
                        localSol.setRepetitionTerm( move( *s ) );
                        co_yield { localLhsVec, localSol, payload, newC };
                    }
                }
            }
        }
    }
}

#endif
Changes to bs/sema/typecheck.cpp.
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

        if( !bestRule )
            co_return;

        co_yield bestRule->func( lhs, rhs, context );
    }

    TCGen HalfUnify( const Term& lhs, const TypeCheckingContext& context )
    {
        const auto& rules = context.rules()->halfUniRules();

        MatchSolution bestSol;
        optional< TypeCheckingRuleSet::HalfUniRule > bestRule;
        bool ambiguous = false;








|







115
116
117
118
119
120
121
122
123
124
125
126
127
128
129

        if( !bestRule )
            co_return;

        co_yield bestRule->func( lhs, rhs, context );
    }

    optional< Term > HalfUnify( const Term& lhs, TypeCheckingContext& context )
    {
        const auto& rules = context.rules()->halfUniRules();

        MatchSolution bestSol;
        optional< TypeCheckingRuleSet::HalfUniRule > bestRule;
        bool ambiguous = false;

144
145
146
147
148
149
150
151
152
153
154
155
        }

        // Let's not really worry about how to properly report this for now.
        if( ambiguous )
            throw runtime_error( "ambiguous half-unification rule" );

        if( !bestRule )
            co_return;

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







|

|


144
145
146
147
148
149
150
151
152
153
154
155
        }

        // Let's not really worry about how to properly report this for now.
        if( ambiguous )
            throw runtime_error( "ambiguous half-unification rule" );

        if( !bestRule )
            return nullopt;

        return bestRule->func( lhs, context );
    }
}
Changes to bs/sema/typecheck.h.
17
18
19
20
21
22
23
24
25
26
27
    TypeCheckingSolution FindBestTyping( 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 Unify( const Term& lhs, const Term& rhs, const TypeCheckingContext& context );
    TCGen HalfUnify( const Term& lhs, const TypeCheckingContext& context );
}

#endif







|



17
18
19
20
21
22
23
24
25
26
27
    TypeCheckingSolution FindBestTyping( 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 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.
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 "sema.h"

namespace goose::sema
{
    TCGen HalfUnifyVectors( const Vector::container_type< Term >& lTerms, size_t i, const Vector& solutionVec, TypeCheckingContext tcc )
    {
        assert( i < lTerms.size() );

        for( auto&& [u,tcc] : HalfUnify( lTerms[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 HalfUnifyVectors( lTerms, i + 1, vec, tcc );
        }
    }

    TCGen UnifyVectors( 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] : Unify( lTerms[i], rTerms[i], tcc ) )




<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







1
2
3
4















5
6
7
8
9
10
11
#include "sema.h"

namespace goose::sema
{















    TCGen UnifyVectors( 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] : Unify( lTerms[i], rTerms[i], tcc ) )
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
                co_yield TypeCheckVectors( lTerms, rTerms, i + 1, vec, tcc );
        }
    }

    void SetupBasicUnificationRules( TypeCheckingRuleSet& ruleSet )
    {
        // Default half-unification rule
        ruleSet.addHalfUnificationRule( TCRINFOS, ANYTERM( _ ), []( const Term& lhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            // NOTE: the score here is always 0 because:
            // Vectors are going to fall into the vector half-unification rule below,
            // and holes are going to have their own rules. So we only are here for terminal expressions.
            co_yield { lhs, tcc };
        } );

        // Identity unification rule
        ruleSet.addUnificationRule( TCRINFOS, ANYTERM( T ), []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            assert( lhs == rhs );








|




|







35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
                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,
            // and holes are going to have their own rules. So we only are here for terminal expressions.
            return lhs;
        } );

        // Identity unification rule
        ruleSet.addUnificationRule( TCRINFOS, ANYTERM( T ), []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
        {
            assert( lhs == rhs );

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
            // in the end if necessary.
            auto lpv = get< void* >( lhs );
            auto rpv = get< void* >( rhs );
            auto result = lpv == rpv ? lpv : nullptr;
            co_yield { result, tcc };
        } );

        // Half-Unification rule for vectors:
        // They are recursed into and each contained members are half-unified.
        // Note: the repetition term, if any, is ignored. The repetition term is only for vector patterns
        // for now. We'll have to see how to handle variadic functions later.
        ruleSet.addHalfUnificationRule( TCRINFOS, VECOFLENGTH( _ ), []( const Term& lhs, const TypeCheckingContext& tcc ) -> TCGen

        {
            assert( holds_alternative< pvec >( lhs ) );

            const auto& lVector = get< pvec >( lhs );
            const auto& lTerms = lVector->terms();


            if( lTerms.empty() )

            {
                co_yield { lhs, tcc };

                co_return;

            }

            Vector sol;
            co_yield HalfUnifyVectors( lTerms, 0, sol, tcc );
        } );

        // Unification rule for vectors of identical length:
        // They are recursed into and each contained members are unified.
        // Note: the repetition term, if any, is ignored. The repetition term is only for vector patterns
        // for now. We'll have to see how to handle variadic functions later.
        ruleSet.addUnificationRule( TCRINFOS, VECOFLENGTH( VL ), []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen







|
<
<
<
|
>






>
|
>

|
>
|
>


|
<







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
            // in the end if necessary.
            auto lpv = get< void* >( lhs );
            auto rpv = get< void* >( rhs );
            auto result = lpv == rpv ? lpv : nullptr;
            co_yield { result, tcc };
        } );

        // Half-Unification rule for vectors



        ruleSet.addHalfUnificationRule( TCRINFOS, VECOFLENGTH( _ ), []( const Term& lhs, TypeCheckingContext& tcc )
            -> optional< Term >
        {
            assert( holds_alternative< pvec >( lhs ) );

            const auto& lVector = get< pvec >( lhs );
            const auto& lTerms = lVector->terms();

            Vector result;

            for( auto&& t : lTerms )
            {
                auto s = HalfUnify( t, tcc );
                if( !s )
                    return nullopt;
                result.append( *s );
            }

            return TERM( make_shared< Vector >( move( result ) ) );

        } );

        // Unification rule for vectors of identical length:
        // They are recursed into and each contained members are unified.
        // Note: the repetition term, if any, is ignored. The repetition term is only for vector patterns
        // for now. We'll have to see how to handle variadic functions later.
        ruleSet.addUnificationRule( TCRINFOS, VECOFLENGTH( VL ), []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
Changes to bs/sema/uni-holes.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
#include "sema.h"

namespace goose::sema
{
    void SetupHoleUnificationRules( TypeCheckingRuleSet& ruleSet )
    {
        // Anonymous hole half-unification: add 1 to the anon holes count,
        // yield the hole as is.
        ruleSet.addHalfUnificationRule( TCRINFOS,
            HOLE( "_"_sid ),
        []( const Term& lhs, TypeCheckingContext tcc ) -> TCGen
        {
            tcc.addAnonymousHole();
            co_yield { lhs, tcc };
        } );

        // Anonymous hole versus anything: add 1 to the anon holes count,
        // yield the half unification of the rhs
        ruleSet.addUnificationRule( TCRINFOS,
            HOLE( "_"_sid ),
            ANYTERM( _ ),
        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            tcc.addAnonymousHole();

            for( auto&& [s,tcc] : HalfUnify( rhs, tcc.flip() ) )
                co_yield { s, tcc.flip() };
        } );

        // Hole half-unification: Convert it to a numbered hole,
        // If the name wasn't already known, add 1 to the score's unique holes count.
        ruleSet.addHalfUnificationRule( TCRINFOS,
            HolePattern(),
        []( const Term& lhs, TypeCheckingContext tcc ) -> TCGen
        {
            auto lh = *HoleFromIRExpr( lhs );

            if( !lh.name.isNumerical() )
            {
                // This is a named hole: look up its name.
                auto holeIndex = tcc.getLHSHoleIndex( lh.name );
                if( holeIndex != TypeCheckingContext::InvalidIndex )
                {
                    if( !tcc.isHoleLocked( holeIndex ) )
                        co_yield { HOLE( StringId( holeIndex ) ), tcc };
                }
                else
                {
                    // This is a new name: create a new value,
                    // and increment the number of unique holes in the current score.
                    auto index = tcc.createValue();
                    tcc.setLHSHoleIndex( lh.name, index );
                    co_yield { HOLE( StringId( index ) ), tcc };
                }
            }
            else
            {
                // This is already an indexed hole: yield it as is.
                if( !tcc.isHoleLocked( lh.name.id() ) )
                    co_yield { lhs, tcc };
            }


        } );

        // Hole vs anything
        ruleSet.addUnificationRule( TCRINFOS,
            HolePattern(),
            ANYTERM( _ ),
        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen










|


|











|
|






|










|







|






|

>
>







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

namespace goose::sema
{
    void SetupHoleUnificationRules( TypeCheckingRuleSet& ruleSet )
    {
        // Anonymous hole half-unification: add 1 to the anon holes count,
        // yield the hole as is.
        ruleSet.addHalfUnificationRule( TCRINFOS,
            HOLE( "_"_sid ),
        []( const Term& lhs, TypeCheckingContext& tcc )
        {
            tcc.addAnonymousHole();
            return lhs;
        } );

        // Anonymous hole versus anything: add 1 to the anon holes count,
        // yield the half unification of the rhs
        ruleSet.addUnificationRule( TCRINFOS,
            HOLE( "_"_sid ),
            ANYTERM( _ ),
        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
        {
            tcc.addAnonymousHole();

            if( auto s = HalfUnify( rhs, tcc.flip() ) )
                co_yield { *s, tcc.flip() };
        } );

        // Hole half-unification: Convert it to a numbered hole,
        // If the name wasn't already known, add 1 to the score's unique holes count.
        ruleSet.addHalfUnificationRule( TCRINFOS,
            HolePattern(),
        []( const Term& lhs, TypeCheckingContext& tcc ) -> optional< Term >
        {
            auto lh = *HoleFromIRExpr( lhs );

            if( !lh.name.isNumerical() )
            {
                // This is a named hole: look up its name.
                auto holeIndex = tcc.getLHSHoleIndex( lh.name );
                if( holeIndex != TypeCheckingContext::InvalidIndex )
                {
                    if( !tcc.isHoleLocked( holeIndex ) )
                        return HOLE( StringId( holeIndex ) );
                }
                else
                {
                    // This is a new name: create a new value,
                    // and increment the number of unique holes in the current score.
                    auto index = tcc.createValue();
                    tcc.setLHSHoleIndex( lh.name, index );
                    return HOLE( StringId( index ) );
                }
            }
            else
            {
                // This is already an indexed hole: yield it as is.
                if( !tcc.isHoleLocked( lh.name.id() ) )
                    return lhs;
            }

            return nullopt;
        } );

        // Hole vs anything
        ruleSet.addUnificationRule( TCRINFOS,
            HolePattern(),
            ANYTERM( _ ),
        []( const Term& lhs, const Term& rhs, TypeCheckingContext tcc ) -> TCGen
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
                if( index == TypeCheckingContext::InvalidIndex )
                {
                    // This is a new name: create a new value.
                    index = tcc.createValue();
                    tcc.setLHSHoleIndex( h.name, index );
                    auto holeExpr = HOLE( StringId( index ) );

                    for( auto&& [e,tcc] : HalfUnify( rhs, tcc.flip() ) )
                    {
                        tcc.setValue( index, SetComplexity( move( e ), tcc.complexity() - oldComplexity ) );
                        co_yield { move( holeExpr ), tcc.flip() };
                    }

                    co_return;
                }
            }








|

|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
                if( index == TypeCheckingContext::InvalidIndex )
                {
                    // This is a new name: create a new value.
                    index = tcc.createValue();
                    tcc.setLHSHoleIndex( h.name, index );
                    auto holeExpr = HOLE( StringId( index ) );

                    if( auto s = HalfUnify( rhs, tcc.flip() ) )
                    {
                        tcc.setValue( index, SetComplexity( move( *s ), tcc.complexity() - oldComplexity ) );
                        co_yield { move( holeExpr ), tcc.flip() };
                    }

                    co_return;
                }
            }

113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
                    tcc.unlockHole( index );
                    tcc.setValue( index, SetComplexity( move( e ), tcc.complexity() - oldComplexity ) );
                    co_yield { move( holeExpr ), tcc };
                }
            }
            else
            {
                for( auto&& [e,tcc] : HalfUnify( rhs, tcc.flip() ) )
                {
                    tcc.unlockHole( index );
                    tcc.setValue( index, SetComplexity( move( e ), tcc.complexity() - oldComplexity ) );
                    co_yield { move( holeExpr ), tcc.flip() };
                }
            }
        } );

        // Hole vs hole
        ruleSet.addUnificationRule( TCRINFOS,







|


|







115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
                    tcc.unlockHole( index );
                    tcc.setValue( index, SetComplexity( move( e ), tcc.complexity() - oldComplexity ) );
                    co_yield { move( holeExpr ), tcc };
                }
            }
            else
            {
                if( auto s = HalfUnify( rhs, tcc.flip() ) )
                {
                    tcc.unlockHole( index );
                    tcc.setValue( index, SetComplexity( move( *s ), tcc.complexity() - oldComplexity ) );
                    co_yield { move( holeExpr ), tcc.flip() };
                }
            }
        } );

        // Hole vs hole
        ruleSet.addUnificationRule( TCRINFOS,
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
            // stored in the other one. We can't just copy the value over as we would lose the dependency
            // relationship between the two holes.
            const auto& lval = tcc.getValue( lindex );
            const auto& rval = tcc.getValue( rindex );

            if( !rval )
            {
                for( auto&& [e,tcc] : HalfUnify( *lval, tcc ) )
                {
                    tcc.unlockHole( lindex );
                    tcc.unlockHole( rindex );

                    tcc.setValue( rindex, HOLE( StringId( lindex ) ) );
                    co_yield { HOLE( StringId( lindex ) ), tcc };
                }
                co_return;
            }

            if( !lval )
            {
                for( auto&& [e,tcc] : HalfUnify( *rval, tcc.flip() ) )
                {
                    tcc.unlockHole( lindex );
                    tcc.unlockHole( rindex );

                    tcc.setValue( lindex, HOLE( StringId( rindex ) ) );
                    co_yield { HOLE( StringId( rindex ) ), tcc.flip() };
                }







|












|







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
233
            // stored in the other one. We can't just copy the value over as we would lose the dependency
            // relationship between the two holes.
            const auto& lval = tcc.getValue( lindex );
            const auto& rval = tcc.getValue( rindex );

            if( !rval )
            {
                if( HalfUnify( *lval, tcc ) )
                {
                    tcc.unlockHole( lindex );
                    tcc.unlockHole( rindex );

                    tcc.setValue( rindex, HOLE( StringId( lindex ) ) );
                    co_yield { HOLE( StringId( lindex ) ), tcc };
                }
                co_return;
            }

            if( !lval )
            {
                if( HalfUnify( *rval, tcc.flip() ) )
                {
                    tcc.unlockHole( lindex );
                    tcc.unlockHole( rindex );

                    tcc.setValue( lindex, HOLE( StringId( rindex ) ) );
                    co_yield { HOLE( StringId( rindex ) ), tcc.flip() };
                }
Changes to bs/sema/uni-quote.cpp.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
        auto&& [quoted] = *result;
        return quoted;
    }

    void SetupQuoteUnificationRules( TypeCheckingRuleSet& ruleSet )
    {
        ruleSet.addHalfUnificationRule( TCRINFOS, VEC( TSID( quote ), ANYTERM( _ ) ),
            []( const Term& lhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                co_yield { lhs, tcc };
            } );

        ruleSet.addUnificationRule( TCRINFOS, VEC( TSID( quote ), ANYTERM( _ ) ),
            []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                if( lhs == rhs )
                    co_yield { lhs, tcc };







|

|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
        auto&& [quoted] = *result;
        return quoted;
    }

    void SetupQuoteUnificationRules( TypeCheckingRuleSet& ruleSet )
    {
        ruleSet.addHalfUnificationRule( TCRINFOS, VEC( TSID( quote ), ANYTERM( _ ) ),
            []( const Term& lhs, TypeCheckingContext& tcc )
            {
                return lhs;
            } );

        ruleSet.addUnificationRule( TCRINFOS, VEC( TSID( quote ), ANYTERM( _ ) ),
            []( const Term& lhs, const Term& rhs, const TypeCheckingContext& tcc ) -> TCGen
            {
                if( lhs == rhs )
                    co_yield { lhs, tcc };