Skip to content
← Back

src/semantic/symbols/function_group.ghul

1
namespace Semantic.Symbols is
2
use System.NotImplementedException
3
4
use IoC
5
use Logging
6
use Source
7
8
use IR.Values.Value
9
10
use Types.Type
11
12
use Ghul.Pipes
13
14
class FUNCTION_GROUP: Symbol, Types.Typed is
15
_functions: Collections.LIST[Function]
16
17
count: int => _functions.count
18
is_empty: bool => _functions.count == 0
19
20
short_description: string => "{name}(...)"
21
22
describe(context: DESCRIBE_CONTEXT) -> SignaturePart =>
23
PARTS.sequence([
24
PARTS.name(self),
25
PARTS.literal("(...)")
26
])
27
28
describe_kind(context: DESCRIBE_CONTEXT) -> string? => "function group"
29
symbol_kind: SymbolKind => SymbolKind.FUNCTION
30
completion_kind: CompletionKind => CompletionKind.FUNCTION
31
32
is_function_group: bool => true
33
34
// A group is what a symbol store holds under its name, so every
35
// store-level filter (completion, outline, duplicate checks) sees
36
// the group and not its members. It therefore hides exactly when
37
// every member is internal; a group holding a visible member stays
38
// visible so an overload a user wrote is not hidden alongside one
39
// the compiler synthesised.
40
is_internal: bool =>
41
_synthesized \/
42
(_functions.count > 0 /\ (_functions |> all(f => f.is_internal)))
43
44
type: Type
45
46
set_type(value: Type) is type = value; si
47
48
functions: Collections.List[Function] => _functions
49
50
init(location: LOCATION, owner: Scope, name: string) is
51
super.init(location, owner, name)
52
53
type = Types.FUNCTION_GROUP(name, self)
54
_functions = Collections.LIST[Function]()
55
si
56
57
specialize_function_group(type_map: Collections.Map[Symbol,Type], owner: GENERIC) -> FUNCTION_GROUP is
58
let result = cast FUNCTION_GROUP?(memberwise_clone())!
59
60
result.specialized_from = self
61
62
result.type = Types.FUNCTION_GROUP(
63
name,
64
result
65
)
66
67
// Pre-sized empty, filled by add: a LIST(_functions) copy would
68
// duplicate every element only for the loop to overwrite them all.
69
result._functions = Collections.LIST[Function](_functions.count)
70
71
for i in 0.._functions.count do
72
result._functions.add(_functions[i].specialize_function(type_map, owner))
73
od
74
75
return result
76
si
77
78
specialize(type_map: Collections.Map[Symbol,Type], owner: GENERIC) -> Symbol =>
79
specialize_function_group(type_map, owner)
80
81
try_specialize(
82
location: LOCATION,
83
logger: Logger,
84
actual_type_arguments: Collections.List[Type]
85
) -> Symbol?
86
is
87
let result_functions = Collections.LIST[Symbol]()
88
let result = FUNCTION_GROUP(location, owner!, name)
89
90
let expected_argument_counts = Collections.LIST[int]()
91
let arity_matches = Collections.LIST[Function]()
92
93
for f in _functions do
94
if f.is_generic then
95
if f.generic_arguments.count == actual_type_arguments.count then
96
arity_matches.add(f)
97
else
98
expected_argument_counts.add(f.generic_arguments.count)
99
fi
100
fi
101
od
102
103
// Overloads whose constraints the type arguments break are not
104
// candidates, but only an overload the call could have meant is
105
// worth reporting against: when another overload accepts the
106
// type arguments, the call's own arguments choose among those.
107
let accepting = Collections.LIST[Function]()
108
109
for f in arity_matches do
110
let use snapshot = logger.speculate_then_backtrack()
111
112
GENERIC_CONSTRAINT_CHECKER().check_arguments(location, logger, f, f.generic_argument_names, actual_type_arguments)
113
114
let errors = snapshot.backtrack()
115
116
if errors.count == 0 then
117
accepting.add(f)
118
fi
119
od
120
121
let chosen = if accepting.count > 0 then accepting else arity_matches fi
122
123
for f in chosen do
124
if accepting.count == 0 then
125
GENERIC_CONSTRAINT_CHECKER().check_arguments(location, logger, f, f.generic_argument_names, actual_type_arguments)
126
fi
127
128
let sf = f.specialize(actual_type_arguments)
129
130
result.add(cast Function?(sf)!)
131
od
132
133
if result.is_empty then
134
if expected_argument_counts.count > 0 then
135
let counts_string mut = expected_argument_counts |> sort() |> join(", ")
136
let last_comma_index = counts_string.last_index_of(", ")
137
138
if last_comma_index >= 0 then
139
counts_string = counts_string.remove(last_comma_index, 2).insert(last_comma_index, " or ")
140
fi
141
142
logger.error(location, "expected {counts_string} type arguments but found {actual_type_arguments.count}")
143
else
144
logger.error(location, "cannot supply type arguments here")
145
fi
146
147
return null
148
fi
149
150
return result
151
si
152
153
remove(function: Function) is
154
_functions.remove(function)
155
si
156
157
add(function: Function) is
158
_functions.add(function)
159
si
160
161
// Combine this group with a same-named group from an enclosing
162
// scope: all of this group's functions are kept, and an outer
163
// function only joins the overload set when no function here
164
// already covers its override class.
165
merged_over(outer: FUNCTION_GROUP) -> FUNCTION_GROUP is
166
let combined = FUNCTION_GROUP(location, owner!, name)
167
168
let seen = Collections.SET[METHOD_OVERRIDE_CLASS]()
169
170
for f in _functions do
171
seen.add(f.override_class)
172
combined.add(f)
173
od
174
175
for f in outer.functions do
176
if !seen.contains(f.override_class) then
177
combined.add(f)
178
fi
179
od
180
181
return combined
182
si
183
184
add(fg: FUNCTION_GROUP) is
185
_functions.add_range(fg.functions)
186
si
187
188
load(location: LOCATION, from: Value?, loader: SYMBOL_LOADER) -> Value =>
189
loader.load_function_group(from, self)
190
191
call(location: Source.LOCATION, from: Value?, arguments: Collections.List[Value], type: Type?, caller: FUNCTION_CALLER) -> IR.Values.Value => throw NotImplementedException("cannot call unresolved function overload group: {self}")
192
collapse_group_if_single_member() -> Symbols.Symbol =>
193
if _functions.count == 1 then
194
_functions[0]
195
else
196
self
197
fi
198
199
to_string() -> string =>
200
"{description} [{_functions |> join(", ")}]"
201
si
202
si