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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
-
+
-
-
-
-
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
+
-
-
+
+
-
-
+
-
-
+
|
#include "builtins/builtins.h"
//#define OVL_TC_DEBUG
// #define OVL_TC_DEBUG
using namespace goose::sema;
namespace goose::builtins
{
class OverloadSetInvocationRule : public InvocationRule
{
public:
Value resolveInvocation( Context& c, LocationId loc, const Value& callee, const Term& args ) const final
{
ProfileZoneScoped;
public:
Value resolveInvocation(
Context& c, LocationId loc, const Value& callee, const Term& args ) const final
{
ProfileZoneScoped;
auto pOvlSet = *FromValue< ptr< OverloadSet > >( callee );
auto pOvlSet = *FromValue< ptr< OverloadSet > >( callee );
#if TRACY_ENABLE
stringstream sstr;
sstr << pOvlSet->identity();
ProfileZoneName( sstr.str().c_str(), sstr.str().size() );
#endif
#if TRACY_ENABLE
stringstream sstr;
sstr << pOvlSet->identity();
ProfileZoneName( sstr.str().c_str(), sstr.str().size() );
#endif
if( auto ovl = pOvlSet->getResolutionFromCache( args ) )
return ovl->pInvRule->resolveInvocation( c, loc, *ovl->callee, args );
else
return resolve( c, loc, pOvlSet, args );
}
if( auto ovl = pOvlSet->getResolutionFromCache( args ) )
return ovl->pInvRule->resolveInvocation( c, loc, *ovl->callee, args );
else
return resolve( c, loc, pOvlSet, args );
}
private:
Value resolve( Context& c, LocationId loc, const ptr< OverloadSet >& pOvlSet, const Term& args ) const
{
const OverloadSet::Overload* bestOvl = nullptr;
optional< TypeCheckingContext > bestTCC;
optional< Term > bestSol;
private:
Value resolve(
Context& c, LocationId loc, const ptr< OverloadSet >& pOvlSet, const Term& args ) const
{
const OverloadSet::Overload* bestOvl = nullptr;
optional< TypeCheckingContext > bestTCC;
optional< Term > bestSol;
{
ProfileZoneScopedN( "Overload resolution" );
{
ProfileZoneScopedN( "Overload resolution" );
bool ambiguous = false;
bool ambiguous = false;
if( pOvlSet->verboseResolution() )
{
DiagnosticsManager::GetInstance().emitTraceMessage( loc,
std::format( "invoking overload set: {}", pOvlSet->identity() ) );
}
if( pOvlSet->verboseResolution() )
{
DiagnosticsManager::GetInstance().emitTraceMessage(
loc, std::format( "invoking overload set: {}", pOvlSet->identity() ) );
}
auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid, "fwd"_sid ) );
TypeCheckingContext tcc( c );
for( auto&& [s,ovl,tcc] : pOvlSet->typeCheck( callPat, tcc ) )
{
if( tcc.numUnknownValues() )
{
if( pOvlSet->verboseResolution() )
{
DiagnosticsManager::GetInstance().emitTraceMessage(
ovl.callee ? ovl.callee->locationId() : 0,
format( "rejected candidate", tcc.score() ) );
}
continue;
}
auto callPat = PrependToVectorTerm( args, HOLE( "_"_sid, "fwd"_sid ) );
TypeCheckingContext tcc( c );
for( auto&& [s, ovl, tcc] : pOvlSet->typeCheck( callPat, tcc ) )
{
if( tcc.numUnknownValues() )
{
if( pOvlSet->verboseResolution() )
{
DiagnosticsManager::GetInstance().emitTraceMessage(
ovl.callee ? ovl.callee->locationId() : 0,
format( "rejected candidate", tcc.score() ) );
}
continue;
}
auto subs = Substitute( s, tcc );
auto subs = Substitute( s, tcc );
// Typechecking rules often end up stripping part of the original type,
// and we want to invoke the overload where these removals are minimized.
//
// Obvious example: if there is an overload that accepts a reference
// and one that accepts a value of the same type and we started with a
// reference, then we want to call the overload where the typechecking
// solution didn't strip the reference.
//
// So we add the weight of the original arguments to the cost,
// and remove the cost of the typechecking solution to account for that.
int32_t cost = tcc.cost();
cost += GetWeight( callPat );
cost -= GetWeight( subs );
tcc.setCost( cost );
// Typechecking rules often end up stripping part of the original type,
// and we want to invoke the overload where these removals are minimized.
//
// Obvious example: if there is an overload that accepts a reference
// and one that accepts a value of the same type and we started with a
// reference, then we want to call the overload where the typechecking
// solution didn't strip the reference.
//
// So we add the weight of the original arguments to the cost,
// and remove the cost of the typechecking solution to account for that.
int32_t cost = tcc.cost();
cost += GetWeight( callPat );
cost -= GetWeight( subs );
tcc.setCost( cost );
if( pOvlSet->verboseResolution() )
{
DiagnosticsManager::GetInstance().emitTraceMessage(
ovl.callee ? ovl.callee->locationId() : 0,
format( "candidate score: {}", tcc.score() ) );
}
if( pOvlSet->verboseResolution() )
{
DiagnosticsManager::GetInstance().emitTraceMessage(
ovl.callee ? ovl.callee->locationId() : 0,
format( "candidate score: {}", tcc.score() ) );
}
auto score = tcc.score();
if( bestTCC && score < bestTCC->score() )
continue;
auto score = tcc.score();
if( bestTCC && score < bestTCC->score() )
continue;
auto pps = Postprocess( subs, tcc );
if( !pps )
continue;
auto pps = Postprocess( subs, tcc );
if( !pps )
continue;
if( bestTCC && score == bestTCC->score() )
{
ambiguous = true;
continue;
}
if( bestTCC && score == bestTCC->score() )
{
ambiguous = true;
continue;
}
bestTCC = tcc;
bestSol = move( *pps );
bestOvl = &ovl;
ambiguous = false;
}
bestTCC = tcc;
bestSol = move( *pps );
bestOvl = &ovl;
ambiguous = false;
}
if( ambiguous )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage( loc,
"ambiguous function call." );
return PoisonValue();
}
if( ambiguous )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage(
loc, "ambiguous function call." );
return PoisonValue();
}
if( !bestSol )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage( loc,
"function arguments mismatch." );
return PoisonValue();
}
if( !bestSol )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage(
loc, "function arguments mismatch." );
return PoisonValue();
}
#if defined( OVL_TC_DEBUG ) && !defined( NDEBUG )
bestTCC->DumpParamsTraces( cout );
cout << endl;
#endif
}
#if defined( OVL_TC_DEBUG ) && !defined( NDEBUG )
bestTCC->DumpParamsTraces( cout );
cout << endl;
#endif
}
pOvlSet->addResolutionToCache( args, *bestOvl );
pOvlSet->addResolutionToCache( args, *bestOvl );
return bestOvl->pInvRule->invoke( c, loc, *bestOvl->callee, args, *bestSol, *bestTCC );
}
return bestOvl->pInvRule->invoke( c, loc, *bestOvl->callee, args, *bestSol, *bestTCC );
}
};
ptr< InvocationRule >& GetOverloadSetInvocationRule()
{
static ptr< InvocationRule > pRule = make_shared< OverloadSetInvocationRule >();
return pRule;
}
void SetupOverloadSetInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToEIR( Value(
GetValueType< ptr< OverloadSet > >(),
ValueToEIR( Value( GetValueType< ptr< OverloadSet > >(), ANYTERM( _ ) ) ),
ANYTERM( _ ) ) ),
GetOverloadSetInvocationRule() );
}
}
} // namespace goose::builtins
|