Skip to content
← Back

src/syntax/process/compile_generic_application.ghul

1
namespace Syntax.Process is
2
use Logging;
3
use Source;
4
5
use Semantic.Types.Type;
6
7
use IR.Values;
8
9
use Ghul.Pipes;
10
11
// Compiles the type-argument-application family of expressions:
12
// explicit specialization (`x[T]`), ambiguous expressions and
13
// generic applications (the resolved-to-type / resolved-to-
14
// function forms). Split out of COMPILE_EXPRESSIONS, which
15
// delegates the matching visit / pre methods here. The
16
// ambiguous-expression and generic-application bodies live in
17
// their `pre` methods — they re-walk children and suppress the
18
// default traversal — so the visitor's `visit` overrides for
19
// those stay empty.
20
class COMPILE_GENERIC_APPLICATION is
21
_logger: Logger;
22
_symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS;
23
_symbol_loader: Semantic.SYMBOL_LOADER;
24
_unit_variant_constructor: Semantic.UNIT_VARIANT_CONSTRUCTOR;
25
_visitor: ScopedVisitor;
26
27
init(
28
logger: Logger,
29
symbol_use_locations: Semantic.SYMBOL_USE_LOCATIONS,
30
symbol_loader: Semantic.SYMBOL_LOADER,
31
unit_variant_constructor: Semantic.UNIT_VARIANT_CONSTRUCTOR,
32
visitor: ScopedVisitor
33
) is
34
super.init();
35
36
_logger = logger;
37
_symbol_use_locations = symbol_use_locations;
38
_symbol_loader = symbol_loader;
39
_unit_variant_constructor = unit_variant_constructor;
40
_visitor = visitor;
41
si
42
43
visit_explicit_specialization(explicit_specialization: Trees.Expressions.EXPLICIT_SPECIALIZATION) is
44
let left_value = explicit_specialization.left?.value;
45
let left_type = left_value?.type;
46
47
if !left_value? \/ !left_type? then
48
explicit_specialization.value = DUMMY(Semantic.Types.ERROR(), explicit_specialization.location);
49
50
return;
51
fi
52
53
if !left_value.has_symbol then
54
_logger.error(explicit_specialization.location, "can't explicitly specialize this");
55
return;
56
fi
57
58
let symbol: Semantic.Symbols.Symbol? mut = explicit_specialization.left.value!.symbol;
59
60
symbol =
61
symbol.try_specialize(
62
explicit_specialization.location,
63
_logger,
64
explicit_specialization.types.elements |>
65
map(t => t.type!) |> collect()
66
);
67
68
let load = cast IR.Values.Load.SYMBOL?(explicit_specialization.left.value);
69
let from = load!.from;
70
71
if symbol? then
72
explicit_specialization.value =
73
IR.Values.Load.SYMBOL(from, symbol);
74
else
75
explicit_specialization.value = DUMMY(Semantic.Types.ERROR(), explicit_specialization.location);
76
fi
77
si
78
79
pre_ambiguous_expression(ambiguous_expression: Trees.Expressions.AMBIGUOUS_EXPRESSION) -> bool is
80
if ambiguous_expression.result == Trees.Expressions.AmbiguousExpressionResult.INDEX then
81
if let ambiguous_expression.value? /\ value.is_need_store then
82
ambiguous_expression.index.compile_expressions_state.value = value;
83
fi
84
85
ambiguous_expression.index.walk(_visitor);
86
87
ambiguous_expression.compile_expressions_state.value = ambiguous_expression.index.value;
88
89
return true;
90
fi
91
92
let arg = ambiguous_expression.type_arguments.elements[0];
93
94
arg.walk(_visitor);
95
96
let symbol: Semantic.Symbols.Symbol? mut = _;
97
98
if ambiguous_expression.left? then
99
ambiguous_expression.left.walk(_visitor);
100
101
if ambiguous_expression.left!.value? then
102
symbol = ambiguous_expression.left!.value!.type!.find_member(ambiguous_expression.identifier.name);
103
104
// find member will not report an error for not found
105
if !symbol? then
106
_logger.error(ambiguous_expression.identifier.location, "member {ambiguous_expression.identifier.name} not found in {ambiguous_expression.left!.value!.type}");
107
fi
108
fi
109
else
110
symbol = _visitor.find(ambiguous_expression.identifier);
111
fi
112
113
if !symbol? then
114
return true;
115
fi
116
117
_symbol_use_locations.add_symbol_use(ambiguous_expression.identifier.location, symbol);
118
119
let result_type: Semantic.Types.Type? mut = _;
120
let result_symbol: Semantic.Symbols.Symbol? mut = _;
121
122
if symbol.is_type then
123
ambiguous_expression.result = Trees.Expressions.AmbiguousExpressionResult.TYPE;
124
result_type =
125
specialize_type(
126
ambiguous_expression.location,
127
symbol,
128
ambiguous_expression.type_arguments
129
);
130
elif symbol.is_function \/ symbol.is_function_group then
131
ambiguous_expression.result = Trees.Expressions.AmbiguousExpressionResult.FUNCTION;
132
result_symbol =
133
specialize_symbol(
134
ambiguous_expression.location,
135
symbol,
136
ambiguous_expression.type_arguments
137
);
138
else
139
_logger.error(ambiguous_expression.location, "cannot apply type arguments here");
140
return true;
141
fi
142
143
let result = ambiguous_expression.result;
144
145
if result == Trees.Expressions.AmbiguousExpressionResult.UNKNOWN then
146
// we didn't resolve what this was in the resolve type expressions phase
147
// don't report another error here, just produce a propagating error value:
148
ambiguous_expression.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), ambiguous_expression.location);
149
elif result == Trees.Expressions.AmbiguousExpressionResult.INDEX then
150
// if the ambiguous expression resolved to an indexer
151
// call then walk that
152
ambiguous_expression.index.walk(_visitor);
153
154
// our value is whatever value the index expression produced
155
ambiguous_expression.compile_expressions_state.value = ambiguous_expression.index.value;
156
elif result == Trees.Expressions.AmbiguousExpressionResult.TYPE then
157
let variant = cast Semantic.Symbols.VARIANT?(symbol);
158
159
if variant? /\ variant.is_unit_variant then
160
let lowered = _unit_variant_constructor.try_load(ambiguous_expression.location, variant, result_type, ambiguous_expression);
161
162
if lowered? then
163
_symbol_use_locations.add_symbol_use(ambiguous_expression.identifier.location, lowered.constructor);
164
ambiguous_expression.compile_expressions_state.value = lowered.value;
165
return true;
166
fi
167
fi
168
169
ambiguous_expression.compile_expressions_state.value = TYPE_EXPRESSION(result_type!, ambiguous_expression.location);
170
elif result == Trees.Expressions.AmbiguousExpressionResult.FUNCTION then
171
let left_value: Value? =
172
if ambiguous_expression.left? then
173
ambiguous_expression.left.value;
174
else
175
null
176
fi;
177
178
ambiguous_expression.compile_expressions_state.value = result_symbol!.load(ambiguous_expression.location, left_value!, _symbol_loader);
179
else
180
assert false else "result variant is something unexpected {result}";
181
fi
182
183
return true;
184
si
185
186
pre_generic_application(generic_application: Trees.Expressions.GENERIC_APPLICATION) -> bool is
187
generic_application.type_arguments.walk(_visitor);
188
189
let symbol: Semantic.Symbols.Symbol? mut = _;
190
191
if generic_application.left? then
192
generic_application.left.walk(_visitor);
193
194
if generic_application.left!.value? then
195
symbol = generic_application.left!.value!.type!.find_member(generic_application.identifier.name);
196
197
// find member will not report an error for not found
198
if !symbol? then
199
_logger.error(generic_application.identifier.location, "member {generic_application.identifier.name} not found in {generic_application.left!.value!.type}");
200
fi
201
fi
202
else
203
// find will report an error for not found
204
symbol = _visitor.find(generic_application.identifier);
205
fi
206
207
if !symbol? then
208
return true;
209
fi
210
211
_symbol_use_locations.add_symbol_use(generic_application.identifier.location, symbol);
212
213
let result_type: Semantic.Types.Type? mut = _;
214
let result_symbol: Semantic.Symbols.Symbol? mut = _;
215
216
if symbol.is_type then
217
generic_application.result = Trees.Expressions.AmbiguousExpressionResult.TYPE;
218
219
result_type =
220
specialize_type(
221
generic_application.location,
222
symbol,
223
generic_application.type_arguments
224
);
225
elif symbol.is_function \/ symbol.is_function_group then
226
generic_application.result = Trees.Expressions.AmbiguousExpressionResult.FUNCTION;
227
228
result_symbol =
229
specialize_symbol(
230
generic_application.location,
231
symbol,
232
generic_application.type_arguments
233
);
234
else
235
_logger.error(generic_application.location, "cannot apply type arguments here");
236
return true;
237
fi
238
239
let result = generic_application.result;
240
241
if result == Trees.Expressions.AmbiguousExpressionResult.UNKNOWN then
242
// we didn't resolve what this was in the resolve type expressions phase
243
// don't report another error here, just produce a propagating error value:
244
generic_application.compile_expressions_state.value = DUMMY(Semantic.Types.ERROR(), generic_application.location);
245
elif result == Trees.Expressions.AmbiguousExpressionResult.TYPE then
246
let variant = cast Semantic.Symbols.VARIANT?(symbol);
247
248
if variant? /\ variant.is_unit_variant then
249
let lowered = _unit_variant_constructor.try_load(generic_application.location, variant, result_type, generic_application);
250
251
if lowered? then
252
_symbol_use_locations.add_symbol_use(generic_application.identifier.location, lowered.constructor);
253
generic_application.compile_expressions_state.value = lowered.value;
254
return true;
255
fi
256
fi
257
258
generic_application.compile_expressions_state.value = TYPE_EXPRESSION(result_type!, generic_application.location);
259
elif result == Trees.Expressions.AmbiguousExpressionResult.FUNCTION then
260
let left_value: Value? =
261
if generic_application.left? then
262
generic_application.left.value;
263
else
264
null
265
fi;
266
267
generic_application.compile_expressions_state.value = result_symbol!.load(generic_application.location, left_value!, _symbol_loader);
268
else
269
assert false else "result is something unexpected {result}";
270
fi
271
272
return true;
273
si
274
275
specialize_type(location: Source.LOCATION, symbol: Semantic.Symbols.Symbol, arguments: Trees.TypeExpressions.LIST) -> Semantic.Types.Type is
276
let resolved_symbol: Semantic.Symbols.Symbol mut = symbol;
277
let group = cast Semantic.Symbols.TYPE_GROUP?(symbol);
278
279
if group? then
280
let match = group.find_by_generic_arguments_count(arguments.elements.count);
281
282
if !match? then
283
let counts = group.generic_arguments_counts |> map(a -> string => "{a}") |> join(" or ");
284
_logger.error(location, "expected {counts} type arguments but found {arguments.elements.count}");
285
return Semantic.Types.ERROR();
286
fi
287
288
resolved_symbol = match;
289
fi
290
291
if !isa Semantic.Symbols.Classy(resolved_symbol) then
292
_logger.error(location, "cannot supply type arguments here");
293
return Semantic.Types.ERROR();
294
fi
295
296
for a in arguments do
297
a.check_is_not_void(_logger, "cannot use void type here");
298
299
let t = a.type;
300
301
if t? /\ t.is_named /\ cast Semantic.Types.NAMED?(t)!.symbol.is_unsafe_constraints then
302
_logger.warn(a.location, "unchecked-constraints", "type {t} has unchecked constraints");
303
fi
304
od
305
306
let classy = resolved_symbol;
307
308
let actual_arguments = arguments |> map(
309
// FIXME type inference issue
310
a -> Type => if a.type? then a.type! else Semantic.Types.ERROR() fi
311
) |> collect();
312
313
let result = Semantic.Types.GENERIC(location, classy, actual_arguments);
314
315
classy.check_argument_constraints(location, _logger, actual_arguments);
316
317
if resolved_symbol.is_unsafe_constraints then
318
_logger.warn(location, "unchecked-constraints", "type {result} has unchecked constraints");
319
fi
320
321
return result;
322
si
323
324
specialize_symbol(location: Source.LOCATION, symbol: Semantic.Symbols.Symbol, arguments: Trees.TypeExpressions.LIST) -> Semantic.Symbols.Symbol? is
325
return
326
symbol.try_specialize(
327
location,
328
_logger,
329
arguments.elements |>
330
map(t => t.type!) |> collect()
331
);
332
si
333
si
334
si