Goose  Diff

Differences From Artifact [0accef60fd]:

  • File bs/builtins/types/runtime/unify.cpp — part of check-in [18e3bfa195] at 2019-08-03 23:38:56 on branch trunk — Fixed the ct_int unification rule, which didn't work correctly against generic function parameters. (user: achavasse size: 7838)

To Artifact [a27a4d237c]:

  • File bs/builtins/types/runtime/unify.cpp — part of check-in [5a80915ee6] at 2019-08-04 00:04:57 on branch trunk — Apply the ct_int unification fix to ct_string unification. (user: achavasse size: 8991)

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
            co_yield { rhs, c };
        } );

        // ct_int constant unification against any other value:
        // Unify the value's type with ct_int, and if successful
        // (as per the rule of ct_int versus rtint above), wrap
        // the result in a callback.
        // That callback will check  that the final unified value is
        // of an RTInt type of suitable
        // size. If it is, it wil emit a load const int instruction.
        // Otherwise, it will fail the unification.
        //
        // The reason we do all this is because we have to resolve the
        // type unification first. It is only after this is done (and any
        // hole is replaced with its infered value) that we know the actual
        // wanted type for the value. We need to know that type to know if
        // our constant value can be converted, and to emit the conversion.
        //
        // So we do this in a callback, which lets us perform a check and
        // substitution of the final value after any contained hole has been
        // replaced, and unification callback has been applied.
        //
        // An example of situation where this is needed is as follow:
        //
        // void lomarf( $T a, $T b ) {}
        // RTUint( 8 ) someInt;
        // lomarf( someInt, 123 );
        //
        // $T will resolve to RTUInt( 8 ), but if we had a simple ct_int against
        // RTUInt param unification rule, the rule wouldn't work, because before we
        // apply substitutions, the second parameter is still expressed as $T b,
        // which would match the rule.
        // However, the ct_int against "value with placeholder type and content" will
        // match against $T b, and wrap it with a callback. Substitute will then
        // turn $T b into RTUInt( 8 ) b and then invoke the callback on that, which
        // can do its final checks and emit the load const int instruction wrapped as
        // a value, or return nullopt to indicate that the unification failed (in case
        // the constant is too big to fit in the RTUInt( 8 )).
        e.unificationRuleSet()->addAsymRule(







|

















|





|







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
            co_yield { rhs, c };
        } );

        // ct_int constant unification against any other value:
        // Unify the value's type with ct_int, and if successful
        // (as per the rule of ct_int versus rtint above), wrap
        // the result in a callback.
        // That callback will check that the final unified value is
        // of an RTInt type of suitable
        // size. If it is, it wil emit a load const int instruction.
        // Otherwise, it will fail the unification.
        //
        // The reason we do all this is because we have to resolve the
        // type unification first. It is only after this is done (and any
        // hole is replaced with its infered value) that we know the actual
        // wanted type for the value. We need to know that type to know if
        // our constant value can be converted, and to emit the conversion.
        //
        // So we do this in a callback, which lets us perform a check and
        // substitution of the final value after any contained hole has been
        // replaced, and unification callback has been applied.
        //
        // An example of situation where this is needed is as follow:
        //
        // void lomarf( $T a, $T b ) {}
        // RTUInt( 8 ) someInt;
        // lomarf( someInt, 123 );
        //
        // $T will resolve to RTUInt( 8 ), but if we had a simple ct_int against
        // RTUInt param unification rule, the rule wouldn't work, because before we
        // apply substitutions, the second parameter is still expressed as $T b,
        // which wouldn't match the rule.
        // However, the ct_int against "value with placeholder type and content" will
        // match against $T b, and wrap it with a callback. Substitute will then
        // turn $T b into RTUInt( 8 ) b and then invoke the callback on that, which
        // can do its final checks and emit the load const int instruction wrapped as
        // a value, or return nullopt to indicate that the unification failed (in case
        // the constant is too big to fit in the RTUInt( 8 )).
        e.unificationRuleSet()->addAsymRule(
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
                // additional unique hole for the second overload would be ignored in the ranking.
                uc.incComplexity( 2 );

                // Yield a value of the unified type, wrapped into a callback
                // that will perform the size check and emit the load const once
                // we know the final unified solution for the value's type.
                // Also, the callback should just return the final valus as is if
                // is happens tobe a ct_int.
                valPat->type() = s;

                auto wrapped = WrapWithCallback( ValueToIRExpr( *valPat ),
                    [rhs]( auto&& t ) -> optional< Term >
                    {
                        auto lhsVal = *ValuePatternFromIRExpr( t );








|







88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
                // additional unique hole for the second overload would be ignored in the ranking.
                uc.incComplexity( 2 );

                // Yield a value of the unified type, wrapped into a callback
                // that will perform the size check and emit the load const once
                // we know the final unified solution for the value's type.
                // Also, the callback should just return the final valus as is if
                // is happens to be a ct_int.
                valPat->type() = s;

                auto wrapped = WrapWithCallback( ValueToIRExpr( *valPat ),
                    [rhs]( auto&& t ) -> optional< Term >
                    {
                        auto lhsVal = *ValuePatternFromIRExpr( t );

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
            ANYTERM( _ ),
            TSID( rt_integer ), TERM( 8ULL ), ANYTERM( _ ) ) );

        auto rtInt8PtrTypePattern = Value( TypeType(), TVEC( TSID( rt_type ),
            ANYTERM( _ ),
            TSID( rt_pointer ), ValueToIRExpr( rtInt8TypePattern ) ) );











        // ct_string constant unification against a rt_pointer to a rt_integer( 8 ):
        // Emit a LoadConstantStr llr instruction.


        e.unificationRuleSet()->addSymRule(




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




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



        []( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen


        {
            auto str = *FromValue< string >( *ValueFromIRExpr( lhs ) );
            auto rhsVal = *ValuePatternFromIRExpr( rhs );





            co_yield { ValueToIRExpr(
                BuildComputedValue( rhsVal.type(), llr::LoadConstStr( str ) ) ), c };





        } );
    }
}







>
>
>
>
>
>
>
>
>
>

|
>
>
|
>
>
>





>
>
>
|
|
|
<
|
>
>
|
>
>
|
<
|

>
>
>
>
|
|
>
>
>
>
>



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
            ANYTERM( _ ),
            TSID( rt_integer ), TERM( 8ULL ), ANYTERM( _ ) ) );

        auto rtInt8PtrTypePattern = Value( TypeType(), TVEC( TSID( rt_type ),
            ANYTERM( _ ),
            TSID( rt_pointer ), ValueToIRExpr( rtInt8TypePattern ) ) );

        // ct_int type against a against a rt_pointer to a rt_integer( 8 ):
        // return the later.
        e.unificationRuleSet()->addSymRule(
            GetValueType< string >(),
            ValueToIRExpr( rtInt8PtrTypePattern ),
        []( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
        {
            co_yield { rhs, c };
        } );

        // ct_string constant unification against a rt_pointer to a rt_integer( 8 ):
        // Emit a LoadConstantStr llr instruction from an unification callback.
        // This works the same way as the ct_int value unification rule, see
        // above for the grisly details.
        e.unificationRuleSet()->addAsymRule(

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

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

        []( const Term& lhs, const Term& rhs, UnificationContext& c ) -> UniGen
        {
            // Unify the type
            auto valPat = ValuePatternFromIRExpr( lhs );

            for( auto&& [s, uc] : Unify( valPat->type(), GetValueType< string >(), c ) )

            {
                uc.incComplexity( 2 );
                valPat->type() = s;

                auto wrapped = WrapWithCallback( ValueToIRExpr( *valPat ),
                    [rhs]( auto&& t ) -> optional< Term >
                    {

                        auto lhsVal = *ValuePatternFromIRExpr( t );

                        if( lhsVal.type() == GetValueType< string >() )
                            return rhs;

                        const auto* str = FromValue< string >( *ValueFromIRExpr( rhs ) );
                        return ValueToIRExpr(
                            BuildComputedValue( lhsVal.type(), llr::LoadConstStr( *str ) ) );
                    }
                );

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