Skip to content
← Back

src/syntax/process/compile_tuples.ghul

1
namespace Syntax.Process is
2
use System.Exception;
3
4
use Logging;
5
6
use Semantic.LEAST_UPPER_BOUND_MAP;
7
use Semantic.Types.Type;
8
9
use IR.Values;
10
use IR.VALUE_BOXER;
11
12
use Ghul.Pipes;
13
14
// Compiles tuple and list/array (`SEQUENCE`) literal expressions.
15
// Split out of COMPILE_EXPRESSIONS, which delegates pre(tuple),
16
// visit(tuple) and the inner sequence compile here. The
17
// exception-handling and walk orchestration for visit(sequence)
18
// stays on the visitor; visit_sequence is the enclosed logic.
19
class COMPILE_TUPLES is
20
_logger: Logger;
21
_innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup;
22
_value_boxer: VALUE_BOXER;
23
_visitor: Syntax.Visitor;
24
_placeholder_resolver: Semantic.SETTLED_PLACEHOLDER_RESOLVER;
25
26
init(
27
logger: Logger,
28
innate_symbol_lookup: Semantic.Lookups.InnateSymbolLookup,
29
value_boxer: VALUE_BOXER,
30
visitor: Syntax.Visitor
31
) is
32
super.init();
33
34
_logger = logger;
35
_innate_symbol_lookup = innate_symbol_lookup;
36
_value_boxer = value_boxer;
37
_visitor = visitor;
38
_placeholder_resolver = Semantic.SETTLED_PLACEHOLDER_RESOLVER();
39
si
40
41
pre_tuple(tuple: Trees.Expressions.TUPLE) -> bool is
42
if tuple.elements.expressions.count == 1 then
43
// Single-element TUPLE is a parenthesised expression
44
// (TUPLE.visit unwraps its value). Forward whatever
45
// constraint applies to the outer expression directly
46
// to the inner one — splitting a value-tuple constraint
47
// across a phantom 1-tuple slot would push the wrong
48
// element type down into the inner expression.
49
if tuple.expected_type? then
50
tuple.elements.expressions[0].set_expected_type(tuple.expected_type, tuple.expected_type_error_message);
51
else
52
tuple.elements.expressions[0].clear_expected_type();
53
fi
54
elif let tuple.expected_type? /\ expected_type.is_value_tuple then
55
for (element, type) in tuple.elements |> zip(expected_type.arguments) do
56
element.set_expected_type(type, tuple.expected_type_error_message);
57
od
58
else
59
for element in tuple.elements do
60
element.clear_expected_type();
61
od
62
fi
63
64
return false;
65
si
66
67
visit_tuple(tuple: Trees.Expressions.TUPLE) is
68
// A type ascription on a parenthesised group only means
69
// something when the group turns out to be a lambda's
70
// destructured parameter, which consumes it before any
71
// value is compiled. Reaching here with one still attached
72
// means the group is an ordinary tuple value, where the
73
// ascription has no effect and would otherwise be dropped
74
// in silence.
75
if let tuple.type_expression? then
76
_logger.error(type_expression.location, "type not allowed here");
77
fi
78
79
let names: Collections.LIST[string]? mut = Collections.LIST[string]();
80
let values = Collections.LIST[Value]();
81
let types = Collections.LIST[Type]();
82
83
let element_constraints: Collections.List[Type]? mut = null;
84
let expected_type_error_message: string? mut = null;
85
86
if let tuple.expected_type? /\ expected_type.is_value_tuple then
87
element_constraints = expected_type.arguments;
88
expected_type_error_message = tuple.expected_type_error_message;
89
fi;
90
91
if tuple.elements.expressions.count == 1 then
92
// A single parenthesised element is a grouped expression,
93
// not a tuple — there are no single-element tuples (a bare
94
// `(x)` is just `x`). A named/typed sole element (`(x = 1)`
95
// / `(x: int)`) is an attempt at one; report it rather than
96
// collapsing to the element's unset value, which would
97
// poison to ERROR and crash IL emission far downstream.
98
if let element: Trees.Expressions.TUPLE_ELEMENT = tuple.elements.expressions[0] then
99
_logger.error(element.location, "single-element tuples are not supported; a tuple needs two or more elements");
100
tuple.compile_expressions_state.value = IR.Values.DUMMY(Semantic.Types.ERROR(), tuple.location);
101
else
102
tuple.compile_expressions_state.value = tuple.elements.expressions[0].value;
103
fi
104
return;
105
elif tuple.elements.expressions.count == 0 then
106
tuple.compile_expressions_state.value = IR.Values.DUMMY(Semantic.Types.ERROR(), tuple.location);
107
108
_logger.error(tuple.location, "empty tuple");
109
return;
110
fi
111
112
let seen_any_named mut = false;
113
114
for (index, v) in tuple.elements |> index() do
115
let element_type_constraint =
116
if element_constraints? then
117
element_constraints[index];
118
else
119
null;
120
fi;
121
122
if isa Trees.Expressions.TUPLE_ELEMENT(v) then
123
let element = v;
124
125
seen_any_named = true;
126
names.add(element.name.name);
127
128
// An attribute pragma only makes sense on a lambda
129
// parameter — reaching here means the parenthesised
130
// list was never rewritten into one (no `->`/`=>`/
131
// `is`/`rec` followed), so this is a genuine tuple
132
// literal instead.
133
if element.pragmas? then
134
for pragma in element.pragmas do
135
_logger.error(pragma.location, "attribute is not allowed here");
136
od
137
fi
138
139
if element.initializer? then
140
if Value.check_is_consumable(_logger, element.initializer.location, element.initializer.value) then
141
if element.type_expression.type? then
142
let expr_type = element.type_expression.type!;
143
let type =
144
if element_type_constraint? then
145
element_type_constraint
146
else
147
expr_type
148
fi;
149
150
let init_value = element.initializer!.value!;
151
152
if element.type_expression.check_is_not_reference(_logger, "tuple element cannot be a reference") then
153
if !type.is_assignable_from(init_value.type!) then
154
_logger.error(element.location, "{init_value.type} is not assignable to {type}");
155
elif element_type_constraint? /\ !element_type_constraint.is_assignable_from(expr_type) then
156
_logger.error(
157
element.type_expression.location,
158
string.format(expected_type_error_message!, [expr_type, element_type_constraint]:object));
159
fi
160
fi
161
162
types.add(type);
163
values.add(_value_boxer.box_if_needed(init_value, type));
164
165
elif element_type_constraint? then
166
let type = element_type_constraint;
167
let init_value = element.initializer!.value!;
168
169
if !type.is_assignable_from(init_value.type!) then
170
_logger.error(
171
element.location,
172
string.format(expected_type_error_message!, [init_value.type!, type]:object));
173
fi
174
175
types.add(type);
176
values.add(_value_boxer.box_if_needed(init_value, type));
177
else
178
let init_value = element.initializer!.value!;
179
types.add(init_value.type!);
180
values.add(init_value);
181
fi
182
183
continue;
184
fi
185
else
186
_logger.error(element.location, "tuple element must have a value");
187
fi
188
189
values.add(IR.Values.DUMMY(Semantic.Types.ERROR(), element.location));
190
types.add(Semantic.Types.ERROR());
191
192
elif Value.check_is_consumable(_logger, v.location, v.value) then
193
let v_value = v.value!;
194
195
if v.is_identifier then
196
// An unnamed element that is a plain identifier
197
// takes its name from that identifier: `(a, b)`
198
// is `(a = a, b = b)`. TUPLE_ELEMENT_NAME owns
199
// the underscore-strip corner cases.
200
let identifier_name = v.try_copy_as_identifer()!.name;
201
let is_field_symbol =
202
isa IR.Values.Load.SYMBOL(v_value) /\
203
v_value.has_symbol /\
204
v_value.symbol.is_field;
205
206
names.add(TUPLE_ELEMENT_NAME.infer(identifier_name, is_field_symbol));
207
seen_any_named = true;
208
else
209
names.add("{index}");
210
fi
211
212
if element_type_constraint? then
213
let type = element_type_constraint;
214
215
if !type.is_assignable_from(v_value.type!) then
216
_logger.error(
217
v.location,
218
string.format(expected_type_error_message!, [v_value.type!, type]:object));
219
fi
220
221
types.add(type);
222
values.add(_value_boxer.box_if_needed(v_value, type));
223
else
224
types.add(v_value.type!);
225
values.add(v_value);
226
fi
227
else
228
values.add(IR.Values.DUMMY(Semantic.Types.ERROR(), v.location));
229
types.add(Semantic.Types.ERROR());
230
fi
231
232
debug_unindent();
233
od
234
235
if !seen_any_named then
236
names = null;
237
fi
238
239
let type = _innate_symbol_lookup.get_tuple_type(_placeholder_resolver.resolve_all(types), names);
240
tuple.compile_expressions_state.value = TUPLE(type, values);
241
si
242
243
visit_sequence(sequence: Trees.Expressions.SEQUENCE) is
244
let type: Type? mut = _;
245
let have_explicit_type: bool mut = _;
246
247
let elements = Collections.LIST[Trees.Expressions.Expression](sequence.elements);
248
249
let constraint_type: Type? mut = _;
250
if let sequence.expected_type? then
251
constraint_type = expected_type.get_element_type();
252
fi
253
254
if !isa Trees.TypeExpressions.INFER(sequence.type_expression) then
255
if sequence.type_expression.type? then
256
type = sequence.type_expression.type;
257
258
have_explicit_type = true;
259
else
260
// FIXME probably not needed - type pass will have given an error
261
_logger.error(sequence.type_expression.location, "bad explicit type expression");
262
return;
263
fi
264
elif elements.count == 0 then
265
if constraint_type? then
266
type = constraint_type;
267
have_explicit_type = true;
268
else
269
// No elements to infer from and no constraint pushed by
270
// the surrounding context: fall back to an object
271
// element type, the same as a literal whose elements
272
// are all null.
273
_logger.hint(sequence.location, "infer-object-from-list-literal", "specify explicit list literal type to avoid inferring object type here");
274
275
type = _innate_symbol_lookup.get_object_type();
276
fi
277
else
278
let seen_any mut = false;
279
let seen_error mut = false;
280
let all_tuple_literals mut = elements.count > 0; // assume all tuples until proved otherwise
281
let tuples_element_count mut = -1;
282
let lub = LEAST_UPPER_BOUND_MAP();
283
284
for v in elements do
285
if !v.is_tuple_literal then
286
all_tuple_literals = false;
287
fi
288
289
if let v.value? /\ value.type? then
290
if value.check_is_consumable(_logger, v.location) then
291
if !value.type!.is_null then
292
seen_any = true;
293
lub.add(value.type!);
294
elif value.type!.is_error then
295
seen_error = true;
296
fi
297
298
if v.is_tuple_literal then
299
if tuples_element_count == -1 then
300
tuples_element_count = value.type!.arguments.count;
301
elif value.type!.arguments.count != tuples_element_count then
302
all_tuple_literals = false;
303
fi
304
fi
305
else
306
seen_error = true;
307
fi
308
else
309
seen_error = true;
310
fi
311
od
312
313
if !type? then
314
type = lub.get_result();
315
316
if all_tuple_literals /\ (!type? \/ !type.is_value_tuple) then
317
let tuple_types = Collections.LIST[Type]();
318
319
for element in elements do
320
if let element.value? /\ value.type? then
321
tuple_types.add(value.type!);
322
fi
323
od
324
325
type = Semantic.TUPLE_ELEMENT_LUB(_innate_symbol_lookup).combine(tuple_types, lub.element_names);
326
327
// going to walk the elements again, so roll back
328
// and re-speculate to avoid duplicate / misleading
329
// error messages
330
_logger.roll_back();
331
_logger.speculate();
332
333
// re-walk the type expression if present, to avoid
334
// hiding any error message it may generate
335
336
sequence.type_expression.walk(_visitor);
337
338
for e in sequence.elements do
339
e.set_expected_type(type, "element type {{0}} not compatible with inferred list type {{1}}");
340
e.walk(_visitor);
341
od
342
fi
343
fi
344
345
// Reconcile bottom-up LUB with any constraint pushed
346
// by the parent context. Prefer the more-specific
347
// bottom-up type when it satisfies the constraint —
348
// that preserves the runtime allocation precision the
349
// covariance idiom relies on (e.g. `let ao: object[]
350
// = ["a", "b"];` should produce a string[] at run
351
// time, even though the variable is declared
352
// object[]). When the LUB doesn't satisfy the
353
// constraint, fall back to the constraint's element
354
// type and drive per-element mismatch errors via the
355
// post-walk assignability check.
356
if constraint_type? then
357
if !type? \/ !constraint_type.is_assignable_from(type) then
358
type = constraint_type;
359
have_explicit_type = true;
360
fi
361
fi
362
363
if !type? then
364
if seen_error then
365
sequence.compile_expressions_state.value = DUMMY(_innate_symbol_lookup.get_array_type(Semantic.Types.ERROR()), sequence.location);
366
return;
367
elif seen_any then
368
_logger.hint(sequence.location, "specify explicit list literal type to avoid inferring object type here");
369
type = _innate_symbol_lookup.get_object_type();
370
else
371
_logger.error(sequence.location, "cannot infer type of list literal with only null elements");
372
373
sequence.compile_expressions_state.value = DUMMY(_innate_symbol_lookup.get_array_type(Semantic.Types.ERROR()), sequence.location);
374
return;
375
fi
376
fi
377
fi
378
379
let values = Collections.LIST[Value](sequence.elements.expressions.count);
380
381
for v in sequence.elements do
382
if let v.value? /\ value.type? then
383
let u = value.type;
384
385
// FIXME should push explicit type into element as constraint and retry
386
if have_explicit_type /\ !type!.is_assignable_from(value.type!) then
387
_logger.error(v.location, "element not compatible with explicit type");
388
fi
389
390
values.add(v.value!);
391
else
392
values.add(DUMMY(Semantic.Types.ERROR(), v.location));
393
fi
394
od
395
396
sequence.compile_expressions_state.value =
397
SEQUENCE(_innate_symbol_lookup.get_array_type(type!), type, values);
398
si
399
si
400
si