Skip to content
← Back

src/syntax/process/compile-expressions/compile_expressions_variables.ghul

1
namespace Syntax.Process is
2
use System.Exception
3
4
use IO.Std
5
6
use Logging
7
use Source
8
9
use IR.Values
10
use IR.VALUE_CONVERTER
11
use IR.VALUE_BOXER
12
13
use Semantic.LEAST_UPPER_BOUND_MAP
14
use Semantic.Types.Type
15
16
use Syntax.Trees.Definitions.PRAGMA
17
18
use Ghul.Pipes
19
20
21
// Variable-left walks: simple, destructuring and literal leaves, variable visits and
22
// symbol type assignment for destructuring.
23
partial COMPILE_EXPRESSIONS is
24
pre(left: Trees.Variables.SIMPLE_VARIABLE_LEFT) -> bool => false
25
visit(left: Trees.Variables.SIMPLE_VARIABLE_LEFT) is
26
let symbol = find(left.name)
27
28
if symbol? /\ isa Semantic.Types.SettableTyped(symbol) then
29
let typed_symbol = cast Semantic.Types.SettableTyped(symbol)
30
let left_state = _variable_left_state.get_or_add(left)
31
32
symbol.define()
33
34
let right_location =
35
if left_state.right_location? then
36
left_state.right_location
37
else
38
left.location
39
fi
40
41
// Iterative-inference re-narrowing: an iter-N type
42
// that's a sentinel or contains a placeholder may
43
// be overwritten on iter N+1 with the now-narrower
44
// value (e.g. Function[placeholder, int] →
45
// Function[int, int] once the lambda arg resolves).
46
//
47
// is_settled alone isn't enough: an overload candidate
48
// that loses to a sibling can still leave its own
49
// still-unbound method type-parameter committed as
50
// the right-hand value's type on an earlier iter -
51
// e.g. C from a losing >>[A,B,C] candidate that
52
// failed to bind C. That's a real, non-sentinel type,
53
// so is_settled reports it as final - but the
54
// parameter isn't one of this function's own generic
55
// parameters, so it can never mean anything here and
56
// must be re-derived rather than kept.
57
let current_type = typed_symbol.type
58
59
let needs_set mut =
60
!current_type? \/
61
!current_type.is_settled \/
62
current_type.has_function_generic_argument_foreign_to(current_function)
63
64
// An inferred local is typed by its initializer on every
65
// walk: a settled type left on the symbol by an earlier
66
// walk of this body may be narrower than what the
67
// initializer now yields, and a placeholder the
68
// initializer now carries has to be installed for its
69
// uses to back-feed it.
70
if !needs_set /\ !left_state.explicit_type? /\ left_state.right_value? then
71
needs_set = true
72
fi
73
74
if
75
!needs_set /\
76
REFUTABLE_LEAF_RETYPE.needs_retype(
77
left.is_refutable,
78
left_state.explicit_type?,
79
left_state.right_value?
80
)
81
then
82
needs_set = true
83
fi
84
85
if needs_set then
86
if left_state.explicit_type? then
87
typed_symbol.set_type(left_state.explicit_type)
88
elif left_state.right_value? then
89
let right_value = left_state.right_value
90
91
if left_state.awaits_later_use /\ isa Semantic.Symbols.Variable(symbol) then
92
let variable = symbol
93
let placeholder = Semantic.Types.INFERRED_VARIABLE_TYPE(variable)
94
95
typed_symbol.set_type(placeholder)
96
97
let rule =
98
if left_state.awaits_empty_literal then
99
Semantic.OBLIGATIONS.EMPTY_LITERAL
100
else
101
"later_use"
102
fi
103
104
Semantic.OBLIGATIONS.defer(rule, placeholder, left.location)
105
elif !Value.check_is_consumable(_logger, right_location, right_value) then
106
typed_symbol.set_type(Semantic.Types.ERROR())
107
elif
108
_logger.is_clean /\
109
right_value.type!.has_function_generic_argument_foreign_to(current_function) /\
110
!left.is_refutable /\
111
isa Semantic.Symbols.Variable(symbol) /\
112
!(cast Semantic.Symbols.Variable(symbol)).is_mutable_marked
113
then
114
// The initializer resolved to a call whose own
115
// type parameter nothing bound. An immutable
116
// local waits on its later uses for the type,
117
// and the call is typed from that on later walks.
118
let variable = cast Semantic.Symbols.Variable(symbol)
119
let placeholder = Semantic.Types.INFERRED_VARIABLE_TYPE(variable)
120
121
left_state.typed_by_later_use = true
122
123
typed_symbol.set_type(placeholder)
124
125
Semantic.OBLIGATIONS.defer("later_use", placeholder, left.location)
126
elif
127
_logger.is_clean /\
128
right_value.type!.has_function_generic_argument_foreign_to(current_function)
129
then
130
// The initializer resolved to a call whose
131
// own type parameter nothing bound: neither
132
// its arguments nor any type the context
133
// supplied. There is no type to settle to,
134
// and keeping the parameter would write an
135
// unbound !!N as this variable's type.
136
//
137
// Reported only on an otherwise clean walk:
138
// an unbound parameter reaching here after
139
// some other diagnostic is that diagnostic's
140
// consequence, not a separate fault.
141
_logger.error(right_location, "cannot infer type here")
142
143
typed_symbol.set_type(Semantic.Types.ERROR())
144
elif
145
right_value.type!.is_null /\
146
!right_value.type!.is_error /\
147
isa Semantic.Symbols.Variable(symbol)
148
then
149
// A `null` initializer says only that the
150
// local can be absent; what is later
151
// assigned to it gives the type.
152
let variable = symbol
153
154
if Semantic.INFERENCE_TRACE.add_lower_bound("variables.null_initializer", variable, right_value.type!) then
155
_logger.mark_consumed_any()
156
fi
157
158
let inferred = variable.try_get_inferred_type()
159
160
if inferred? /\ !inferred.is_sentinel then
161
typed_symbol.set_type(inferred)
162
else
163
typed_symbol.set_type(Semantic.Types.INFERRED_VARIABLE_TYPE(variable))
164
fi
165
elif let variable: Semantic.Symbols.Variable = symbol /\ variable.is_mutable_marked then
166
// A `mut` local holds what is assigned to it
167
// later as well as its initializer: its type is
168
// their join, floored so an unrelated assignment
169
// is still reported where it is written.
170
variable.joins_assignments = true
171
172
if Semantic.INFERENCE_TRACE.add_lower_bound("variables.mut_initializer", variable, right_value.type!) then
173
_logger.mark_consumed_any()
174
fi
175
176
typed_symbol.set_type(
177
Semantic.MUT_LOCAL_JOIN().type_for(
178
right_value.type!,
179
variable.try_get_inferred_type(),
180
variable.lower_bounds
181
)
182
)
183
elif Semantic.Types.NULL_ELEMENT.within(right_value.type!) then
184
// A tuple with a `null` element and nothing to say
185
// what that element holds has no type a variable
186
// can take.
187
_logger.error(right_location, "cannot infer type here")
188
189
typed_symbol.set_type(Semantic.Types.ERROR())
190
else
191
typed_symbol.set_type(right_value.type!)
192
fi
193
else
194
// No explicit type and no initializer
195
// (`let l;`). Try the LUB accumulated from
196
// later assignments; otherwise stand-in with
197
// an INFERRED_VARIABLE_TYPE placeholder so
198
// subsequent assignments can attach
199
// constraints and the body retry loop
200
// resolves on iteration N+1.
201
//
202
// !is_sentinel deliberate (not is_settled):
203
// if try_get_inferred_type returns a
204
// composite-with-placeholder LUB, we commit
205
// it on iter N. The needs_set path above
206
// uses is_settled, so iter N+1 picks the
207
// slot up again and may refresh with a
208
// more-resolved value. !is_sentinel accepts
209
// a one-iter delayed convergence in exchange
210
// for not re-deriving the LUB every iter
211
// while it's stable.
212
if isa Semantic.Symbols.Variable(symbol) then
213
let variable = symbol
214
let inferred = variable.try_get_inferred_type()
215
216
if inferred? /\ !inferred.is_sentinel then
217
typed_symbol.set_type(inferred)
218
else
219
typed_symbol.set_type(Semantic.Types.INFERRED_VARIABLE_TYPE(variable))
220
fi
221
fi
222
fi
223
elif
224
left_state.explicit_type? /\
225
left_state.right_value? /\
226
Value.check_is_consumable(_logger, right_location, left_state.right_value)
227
then
228
let explicit_type = left_state.explicit_type!
229
let right_value = left_state.right_value!
230
231
// A value still holding placeholders - a local whose
232
// function literal left a parameter to later use -
233
// learns their types from the declared type, as an
234
// argument learns them from its formal.
235
if right_value.type!.contains_inferred then
236
_overload_resolver.match_propagator.propagate_match(explicit_type, right_value.type)
237
fi
238
239
if
240
!left.is_refutable /\
241
!explicit_type.is_assignable_from(right_value.type!)
242
then
243
// Refutable bindings (`if let p: T = e`) skip
244
// this check: the type ascription is a
245
// runtime narrowing test, the scrutinee is
246
// typically wider than `T`, and the cast may
247
// fail — that's the whole point of the
248
// construct.
249
_logger.error(
250
left_state.variable_location!,
251
"{right_value.type} is not assignable to {explicit_type}")
252
fi
253
fi
254
255
if left_state.right_value? then
256
left_state.value = symbol.store(left.location, null, left_state.right_value, _symbol_loader, true)
257
258
// A non-optional initializer leaves the local
259
// known to hold a value — even where its declared
260
// type is `T?` — so a following dereference does
261
// not warn. Skipped when the local's declared
262
// type is already non-optional (the presence bit
263
// is redundant and the hint would be noise).
264
if
265
isa Semantic.Symbols.Variable(symbol) /\
266
is_non_optional_value(left_state.right_value)
267
then
268
let variable = cast Semantic.Symbols.Variable(symbol)
269
let variable_type = variable.type
270
271
if variable_type? /\ variable_type.is_optional then
272
_flow.mark_non_null(variable)
273
_flow.report_narrowing_site(
274
left.location,
275
"narrowing-assign",
276
"►",
277
INLAY_TYPE.render(variable_type.as_non_optional())
278
)
279
fi
280
fi
281
fi
282
else
283
_logger.error(left.name.location, "couldn't find typed symbol for variable {left.name}")
284
fi
285
si
286
287
pre(left: Trees.Variables.DESTRUCTURING_VARIABLE_LEFT) -> bool is
288
// A destructured formal argument has no initializer to walk
289
// a value from - its leaves' types are already assigned by
290
// resolve-explicit-types from the parameter's aggregate
291
// type, and generate-il sources the unpack directly from
292
// the synthesised parameter symbol. Nothing here applies.
293
if left.is_argument_left then
294
return true
295
fi
296
297
// Per-element type ascription: each element of a destructure
298
// pattern can carry its own `: T` (e.g. `(c: Cat, d: Dog)`,
299
// or recursively `((x: int, y: int): Point, c: Color)`).
300
// Walk the type_expression and pin the element's
301
// `explicit_type` so the bound symbol gets the declared
302
// type rather than the raw source-member type. The runtime
303
// narrowing test for the refutable path is emitted later
304
// by `gen_destructuring_initialize` in generate_il.
305
for e in left.elements do
306
if let e.type_expression? then
307
type_expression.walk(self)
308
309
if let type_expression.type? then
310
_variable_left_state.get_or_add(e).explicit_type = type
311
fi
312
fi
313
od
314
315
let left_state = _variable_left_state.get_or_add(left)
316
317
let from mut = left_state.right_value
318
319
if !from? then
320
_logger.error(left.location, "cannot destructure without initializer")
321
return true
322
fi
323
324
let from_type mut =
325
if left_state.explicit_type? then
326
left_state.explicit_type
327
else
328
from.type
329
fi
330
331
if !from_type? then
332
_logger.error(left.location, "oops: null type")
333
334
from_type = Semantic.Types.ERROR()
335
fi
336
337
// Refutable destructure on an optional source: the `if let`
338
// presence test has already excluded null at this point, so
339
// resolve members against the unwrapped type and load them
340
// from the unwrapped value. A value-type `T?` unwraps via
341
// its synthesised `value` member; a reference `T?` keeps
342
// the same backing value and just drops the optional flag.
343
if left.is_refutable /\ from_type.is_optional then
344
if from_type.is_value_type then
345
let value_member = from_type.find_member("value")
346
347
if value_member? then
348
from = value_member.load(LOCATION.internal, from, _symbol_loader)
349
from_type = from.type!
350
fi
351
else
352
from_type = from_type.as_non_optional()
353
from = IR.Values.TYPE_WRAPPER(from_type, from)
354
fi
355
fi
356
357
// Destructure on a still-unresolved placeholder: emit a
358
// DESTRUCTURE_CONSTRAINT(member_count) on the
359
// placeholder's origin so the body-retry loop can filter
360
// candidate types against it, then defer rather than
361
// hard-erroring "cannot destructure". Without this the
362
// body-retry never gets a useful signal — the destructure
363
// type is fixed and the lambda's RHS placeholder is
364
// forced to resolve via some other use.
365
if isa Semantic.Types.INFERRED_VARIABLE_TYPE(from_type) then
366
let placeholder = from_type
367
let constraint = Semantic.DESTRUCTURE_CONSTRAINT(left.elements.count)
368
369
_logger.mark_consumed_any_if(Semantic.INFERENCE_TRACE.add_constraint("variables.destructure", placeholder.origin, constraint))
370
371
_defer_destructure_leaves(left, from_type)
372
373
return true
374
fi
375
376
// Any other placeholder - a join still waiting on an operand -
377
// has no origin to constrain and is not an error either: an
378
// obligation of this walk, for a later one to settle.
379
if from_type.is_inferred then
380
Semantic.OBLIGATIONS.defer("destructure", from_type, left.location)
381
382
_defer_destructure_leaves(left, from_type)
383
384
return true
385
fi
386
387
let elements = left.elements
388
389
// A group is either all named or all positional: the
390
// parser reports one that mixes the two. It yields the
391
// group anyway, so that the rest of the statement is
392
// still walked, which is the one case where an element
393
// here carries no name while its neighbour does - and
394
// the mixing is already reported, so there is nothing
395
// left to resolve.
396
let is_named_group = elements.count > 0 /\ elements[0].source_field_name?
397
398
let field_names: Collections.List[string?]? mut = null
399
if is_named_group then
400
if elements |> any(element => !element.source_field_name?) then
401
return true
402
fi
403
404
let names = Collections.LIST[string?]()
405
for element in elements do
406
names.add(element.source_field_name!.name)
407
od
408
field_names = names
409
fi
410
411
let strategy = resolve_destructure_strategy(left.location, from_type, elements.count, field_names)
412
413
let block = IR.Values.BLOCK(_innate_symbol_lookup.get_void_type())
414
415
if strategy.is_deconstruct then
416
let deconstruct = strategy.deconstruct_function!
417
418
for i in 0..elements.count do
419
let element = elements[i]
420
let element_type = deconstruct.arguments[i].get_element_type()!
421
422
let element_state = _variable_left_state.get_or_add(element)
423
424
element_state.right_value = IR.Values.DUMMY(element_type, element.location)
425
426
element_state.variable_location = left_state.variable_location
427
element_state.right_location = left_state.right_location
428
429
element.walk(self)
430
431
if element_state.value? then
432
block.add(element_state.value)
433
fi
434
od
435
else
436
let members = strategy.members
437
let get_from = from.get_temp_copier(block, "destructure")
438
439
for i in 0..elements.count do
440
let element = elements[i]
441
let member = members[i]
442
443
if member? then
444
let element_state = _variable_left_state.get_or_add(element)
445
446
element_state.right_value = member.load(LOCATION.internal, get_from(), _symbol_loader)
447
448
element_state.variable_location = left_state.variable_location
449
element_state.right_location = left_state.right_location
450
451
element.walk(self)
452
453
if element_state.value? then
454
block.add(element_state.value)
455
fi
456
fi
457
od
458
fi
459
460
block.close()
461
462
left_state.value = block
463
464
return true
465
si
466
467
// While the source of a destructure is still being inferred, each
468
// name it declares stands as a placeholder of its own, so its uses
469
// bound it rather than finding it undefined. It waits on the source,
470
// which is what a later walk types it from, and what is reported if
471
// nothing does.
472
_defer_destructure_leaves(left: Trees.Variables.VariableLeft, source: Type) is
473
let elements = left.elements
474
475
if !elements? then
476
return
477
fi
478
479
for element in elements do
480
if element.is_simple_name then
481
if let variable: Semantic.Symbols.Variable = find(element.name!) then
482
variable.define()
483
484
if let explicit_type = _variable_left_state.get_or_add(element).explicit_type then
485
variable.set_type(explicit_type)
486
elif !variable.type? \/ !variable.type.is_settled then
487
let placeholder = Semantic.Types.INFERRED_VARIABLE_TYPE(variable)
488
489
variable.set_type(placeholder)
490
491
Semantic.OBLIGATIONS.defer("destructure", source, element.location)
492
fi
493
fi
494
else
495
_defer_destructure_leaves(element, source)
496
fi
497
od
498
si
499
500
visit(destructure_left: Trees.Variables.DESTRUCTURING_VARIABLE_LEFT) is
501
si
502
503
// A literal leaf inside a destructure pattern — a runtime
504
// equality test, not a binding. The expression carries its
505
// own type (literal kinds map to fixed types; an enum-member
506
// name expression types to its enum). The expression is
507
// walked via default descent; the source position's type is
508
// pushed down as a constraint so a `null` leaf picks up the
509
// source position's nullable type (other literal kinds
510
// inherit the constraint as a no-op, since their type is
511
// fixed by their token kind). Literal-vs-source mismatches
512
// are diagnosed eagerly by `visit(LITERAL_VARIABLE_LEFT)`
513
// below, not via the constraint message.
514
pre(left: Trees.Variables.LITERAL_VARIABLE_LEFT) -> bool is
515
let right_value = _variable_left_state.get_or_add(left).right_value
516
517
if right_value? /\ right_value.type? then
518
left.expression.set_expected_type(
519
right_value.type,
520
"literal pattern type {{0}} is not comparable to source position type {{1}}"
521
)
522
fi
523
return false
524
si
525
526
visit(left: Trees.Variables.LITERAL_VARIABLE_LEFT) is
527
// State survives between walks of the same node, so drop any
528
// test a previous walk built before deciding to build one.
529
let leaf_state = _variable_left_state.get_or_add(left)
530
531
leaf_state.match_test = null
532
leaf_state.match_operand = null
533
534
// A matching leaf in a non-refutable context (plain `let`)
535
// is a silent no-op at runtime — the pattern would never
536
// actually test the source value, so subsequent bindings
537
// run as if the leaf were a wildcard. Reject it loudly
538
// here so the user is forced to write either `if let`
539
// / `case`-when (where the leaf becomes an actual
540
// equality test) or remove the leaf.
541
if !left.is_refutable then
542
_logger.error(
543
left.location,
544
"a matching leaf is only allowed inside a refutable binding (if let or case-when arm)"
545
)
546
547
return
548
fi
549
550
// A leaf whose type is incompatible with the source
551
// position's type can never match — the runtime equality
552
// test is statically dead. Reject with a clear diagnostic
553
// here rather than letting the IL emit and surface as a
554
// less helpful comparison-operator error later.
555
if let
556
rv = leaf_state.right_value, source_type = rv.type,
557
ev = left.expression.value, literal_type = ev.type
558
then
559
if
560
!source_type.is_assignable_from(literal_type) /\
561
!literal_type.is_assignable_from(source_type)
562
then
563
_logger.error(
564
left.location,
565
"a leaf of type {literal_type} cannot match source position of type {source_type}"
566
)
567
568
return
569
fi
570
571
_build_literal_leaf_test(left, source_type, ev)
572
fi
573
si
574
575
// Build the runtime test a literal leaf performs against its
576
// source position, the way `=~` (falling back to `<>`) would, so
577
// a leaf whose type declares an equality operator matches by
578
// value rather than by reference. Shares the `case` `when`
579
// label builder, so the two refutable constructs agree on what
580
// a literal matches.
581
//
582
// The source position's value does not exist until IL
583
// generation walks the pattern, so the test is built against a
584
// hole that generation fills in. Leaving the test unbuilt is
585
// always safe: generation falls back to the raw compare, which
586
// is what a bare `==` does too.
587
_build_literal_leaf_test(
588
left: Trees.Variables.LITERAL_VARIABLE_LEFT,
589
source_type: Semantic.Types.Type,
590
literal_value: IR.Values.Value
591
) is
592
// A `null` leaf is a presence test rather than a value
593
// comparison; a null operand would build a null-typed temp
594
// the back end cannot encode. Generation matches absence.
595
if literal_value.type?.is_null ?? false then
596
return
597
fi
598
599
let operand = IR.Values.WRAPPER(IR.Values.DUMMY(source_type, left.location))
600
601
let test =
602
build_equality_test(operand, literal_value, "=~", left.location) ??
603
build_equality_test(operand, literal_value, "<>", left.location)
604
605
if !test? then
606
return
607
fi
608
609
let state = _variable_left_state.get_or_add(left)
610
611
state.match_operand = operand
612
state.match_test = test
613
si
614
615
// The local an initializer `[]` would type, when the literal has
616
// no context of its own: no written type on the literal or the
617
// local, nothing pushed into the literal, and a plain immutable
618
// local to bind. A mutable local joins its later assignments
619
// instead.
620
_empty_literal_awaiting_use(variable: Trees.Variables.VARIABLE, init: Trees.Expressions.Expression) -> Semantic.Symbols.Variable? is
621
if variable.is_explicit_type \/ variable.is_refutable \/ variable.is_argument then
622
return null
623
fi
624
625
let sequence = cast Trees.Expressions.SEQUENCE?(init)
626
627
if
628
!sequence? \/
629
sequence.elements.expressions.count != 0 \/
630
!isa Trees.TypeExpressions.INFER(sequence.type_expression) \/
631
sequence.expected_type?
632
then
633
return null
634
fi
635
636
if let simple: Trees.Variables.SIMPLE_VARIABLE_LEFT = variable.left then
637
if let local: Semantic.Symbols.Variable = find(simple.name) /\ !local.is_mutable_marked then
638
return local
639
fi
640
fi
641
642
return null
643
si
644
645
// The plain immutable local an initializer with no type of its own
646
// is typed from: a `_()` with nothing pushed into it, or a call a
647
// previous walk found leaving a type parameter of its own unbound.
648
_typed_by_later_use(variable: Trees.Variables.VARIABLE, init: Trees.Expressions.Expression) -> Semantic.Symbols.Variable? is
649
if variable.is_explicit_type \/ variable.is_refutable \/ variable.is_argument then
650
return null
651
fi
652
653
if let simple: Trees.Variables.SIMPLE_VARIABLE_LEFT = variable.left then
654
if let local: Semantic.Symbols.Variable = find(simple.name) /\ !local.is_mutable_marked then
655
let state = _variable_left_state.get_or_add(simple)
656
657
if isa Trees.Expressions.CONSTRUCT(init) /\ !init.expected_type? then
658
state.typed_by_later_use = true
659
fi
660
661
if state.typed_by_later_use then
662
return local
663
fi
664
fi
665
fi
666
667
return null
668
si
669
670
pre(variable: Trees.Variables.VARIABLE) -> bool is
671
// Attribute pragmas on a formal-argument parameter — walk
672
// their argument expressions here since this override
673
// suppresses VARIABLE's own default child walk (returns
674
// true below).
675
if variable.pragmas? then
676
for pragma in variable.pragmas do
677
pragma.walk(self)
678
od
679
fi
680
681
variable.type_expression.walk(self)
682
683
// push explicit type down into the variable left
684
if let te_type = variable.type_expression.type /\ variable.is_explicit_type then
685
_variable_left_state.get_or_add(variable.left).explicit_type = te_type
686
fi
687
688
if variable.is_refutable then
689
variable.left.mark_refutable_recursive()
690
fi
691
692
// A bare `_` initializer of a simple local with no
693
// explicit type is treated exactly like a no-initializer
694
// `let`: the type is inferred from later assignments.
695
// `_` only contributes the definite-assignment fact — the
696
// LET deferred-init tracking keys off `initializer?`,
697
// which is true here, so the variable is not warned.
698
let bare_default =
699
isa Trees.Expressions.DEFAULT(variable.initializer) /\
700
!(cast Trees.Expressions.DEFAULT(variable.initializer)).type_expression? /\
701
!variable.is_explicit_type /\
702
variable.left.is_simple_name
703
704
if let init = variable.initializer /\ !bare_default /\ !variable.is_argument then
705
if let te = variable.type_expression, te_type = te.type /\ !isa Trees.TypeExpressions.INFER(te) then
706
// if we have both an explicit type and an initializer, we
707
// can push a type constraint down into the initializer
708
init.set_expected_type(te_type, "{{0}} is not assignable to {{1}}")
709
fi
710
711
// An untyped local initialized with `[]` takes its type
712
// from its later uses: once a walk has settled the local,
713
// the literal is typed from it, and until then the local
714
// waits as a placeholder its uses can bound. The local
715
// whose uses never settle it is defaulted by the fixing
716
// step once the walks have stopped, and this walk is the
717
// one after that: the literal then has no constraint
718
// pushed into it and takes its own object element type.
719
let waits_on_use = _empty_literal_awaiting_use(variable, init)
720
721
let awaits mut = false
722
let empty_literal mut = false
723
724
if let waiting = waits_on_use /\ !Semantic.OBLIGATIONS.has_default_for(waiting) then
725
let inferred = waiting.try_get_inferred_type()
726
727
if Semantic.EMPTY_LITERAL_LOCAL.decide(inferred) == Semantic.EmptyLiteralLocal.TYPE_FROM_USE then
728
init.set_expected_type(inferred!, "{{0}} is not assignable to {{1}}")
729
else
730
awaits = true
731
empty_literal = true
732
fi
733
elif let later = _typed_by_later_use(variable, init) then
734
// No default to fall back to: the local waits until its
735
// uses settle it, and is reported if nothing does.
736
let inferred = later.try_get_inferred_type()
737
738
if inferred? /\ inferred.is_settled then
739
init.set_expected_type(inferred, "{{0}} is not assignable to {{1}}")
740
elif isa Trees.Expressions.CONSTRUCT(init) then
741
init.set_expected_type(Semantic.Types.INFERRED_VARIABLE_TYPE(later), "{{0}} is not assignable to {{1}}")
742
awaits = true
743
fi
744
fi
745
746
let await_state = _variable_left_state.get_or_add(variable.left)
747
748
await_state.awaits_later_use = awaits
749
await_state.awaits_empty_literal = empty_literal
750
751
init.walk(self)
752
753
// push the initializer value down into the variable left
754
let left_state = _variable_left_state.get_or_add(variable.left)
755
756
if let init_value = init.value then
757
left_state.right_value = init_value
758
else
759
left_state.right_value = IR.Values.DUMMY(Semantic.Types.ERROR(), init.location)
760
fi
761
762
left_state.variable_location = variable.location
763
left_state.right_location = init.location
764
fi
765
766
// No-type, no-initializer is now allowed: the variable's
767
// type is inferred from later assignments via the
768
// INFERRED_VARIABLE_TYPE placeholder + LUB accumulator
769
// (#1174 — see visit(SIMPLE_VARIABLE_LEFT) below). If
770
// no assignment ever fires, the placeholder remains
771
// and the variable's first use will produce a
772
// "cannot infer" error.
773
774
variable.left.walk(self)
775
776
// Generator: register the new local on the state-machine
777
// frame so a closure later in the body that captures it
778
// references the frame field rather than a
779
// CLR-local slot that doesn't exist inside MoveNext.
780
// No-op outside a generator function; idempotent on the
781
// field (declare_local_field returns the existing field
782
// and only refreshes its type on subsequent calls).
783
declare_state_machine_local_fields(variable.left)
784
785
return true
786
si
787
788
visit(variable: Trees.Variables.VARIABLE) is
789
// A typed `let x: T = e` — check the initializer against
790
// the declared type. An untyped `let` infers its type
791
// from the initializer, so there is no slot to violate.
792
let type_expression = variable.type_expression
793
let initializer = variable.initializer
794
795
if initializer? then
796
check_non_optional(
797
type_expression.type,
798
initializer,
799
initializer.location
800
)
801
802
_pure_slots.check_store(initializer.location, type_expression.type, initializer.value)
803
fi
804
805
if let pragmas = variable.pragmas then
806
let target = symbol_for(variable)
807
808
for pragma in pragmas do
809
_attribute_resolver.resolve(pragma, target)
810
od
811
fi
812
si
813
814
// TODO used by for loop - needs removing
815
set_symbol_type(left: Trees.Variables.VariableLeft, type: Type) is
816
817
if left.is_simple_name then
818
// is_simple_name => SIMPLE_VARIABLE_LEFT, whose name is non-null
819
let symbol = find(left.name!)
820
821
if symbol? /\ isa Semantic.Types.SettableTyped(symbol) then
822
let typed_symbol = cast Semantic.Types.SettableTyped(symbol)
823
824
symbol.define()
825
826
typed_symbol.set_type(type)
827
else
828
_logger.error(left.location, "couldn't find typed symbol for variable {left.name}")
829
fi
830
else
831
set_symbol_destructure_types(left, type)
832
fi
833
si
834
835
// TODO used by for loop - needs removing
836
set_symbol_destructure_types(left: Trees.Variables.VariableLeft, from_type: Type) is
837
let elements = left.elements
838
839
if !elements? then
840
return
841
fi
842
843
let is_named_group = elements.count > 0 /\ elements[0].source_field_name?
844
845
let field_names: Collections.List[string?]? mut = null
846
if is_named_group then
847
let names = Collections.LIST[string?]()
848
for element in elements do
849
// is_named_group: the parser enforces all-or-nothing
850
// source field names per destructure group
851
names.add(element.source_field_name!.name)
852
od
853
field_names = names
854
fi
855
856
let strategy = resolve_destructure_strategy(left.location, from_type, elements.count, field_names)
857
858
if strategy.is_deconstruct then
859
let deconstruct = strategy.deconstruct_function!
860
861
for i in 0..elements.count do
862
let element = elements[i]
863
864
let element_type = deconstruct.arguments[i].get_element_type()!
865
866
if element.is_simple_name then
867
let symbol = find(element.name!)
868
869
if symbol? /\ isa Semantic.Types.SettableTyped(symbol) then
870
let typed_symbol = cast Semantic.Types.SettableTyped(symbol)
871
872
symbol.define()
873
874
typed_symbol.set_type(element_type)
875
else
876
_logger.error(element.location, "couldn't find typed symbol for destructuring element {element.name}")
877
fi
878
else
879
set_symbol_destructure_types(element, element_type)
880
fi
881
od
882
883
return
884
fi
885
886
let members = strategy.members
887
888
for i in 0..elements.count do
889
let element = elements[i]
890
let member = members[i]
891
892
if member? then
893
let member_type = member.type
894
895
if element.is_simple_name then
896
let symbol = find(element.name!)
897
898
if symbol? /\ isa Semantic.Types.SettableTyped(symbol) then
899
let typed_symbol = cast Semantic.Types.SettableTyped(symbol)
900
901
symbol.define()
902
903
if member_type? then
904
typed_symbol.set_type(member_type)
905
fi
906
else
907
_logger.error(element.location, "couldn't find typed symbol for destructuring element {element.name}")
908
fi
909
elif member_type? then
910
set_symbol_destructure_types(element, member_type)
911
fi
912
fi
913
od
914
si
915
916
// TODO used by for loop - needs removing
917
get_destructure_types(type: Type?) -> Collections.List[Type] is
918
let result = Collections.LIST[Type]()
919
920
if !type? \/ !type.is_value_tuple then
921
return result
922
fi
923
924
get_destructure_types_into(type, result)
925
926
return result
927
si
928
929
// TODO used by for loop - needs removing
930
get_destructure_types_into(type: Type, into: Collections.MutableList[Type]) is
931
let result = Collections.LIST[Type]()
932
933
for t in type.arguments do
934
if t.is_value_tuple then
935
get_destructure_types_into(t, into)
936
else
937
into.add(t)
938
fi
939
od
940
si
941
942
si
943
si