lib/std/lang/resolver.rad 439.6 KiB raw
1
//! Radiance semantic analyzer and type resolver.
2
//!
3
//! This module performs scope construction, symbol binding, and identifier
4
//! resolution on top of the AST produced by the parser.
5
6
export mod printer;
7
8
/// Unit tests for the resolver.
9
@test mod tests;
10
11
// TODO: Move to raw vectors to reduce list duplication?
12
// TODO: When a function declaration fails to typecheck, it should still "exist".
13
// TODO: `ensureNominalResolved` should just run when you call `typeFor`.
14
// TODO: Have different types for positional vs. named field records.
15
16
use std::mem;
17
use std::io;
18
use std::lang::alloc;
19
use std::lang::types;
20
use std::lang::ast;
21
use std::lang::parser;
22
use std::lang::module;
23
24
/// Maximum number of diagnostics recorded.
25
export constant MAX_ERRORS: u32 = 64;
26
27
/// Synthetic function name used when wrapping a bare expression for analysis.
28
export constant ANALYZE_EXPR_FN_NAME: *[u8] = "__expr__";
29
/// Synthetic function name used when wrapping a block for analysis.
30
export constant ANALYZE_BLOCK_FN_NAME: *[u8] = "__block__";
31
32
/// Maximum number of symbols stored within a module scope.
33
export constant MAX_MODULE_SYMBOLS: u32 = 512;
34
/// Maximum number of symbols stored within a local scope.
35
export constant MAX_LOCAL_SYMBOLS: u32 = 32;
36
/// Maximum function parameters.
37
export constant MAX_FN_PARAMS: u32 = 8;
38
/// Maximum function thrown types.
39
export constant MAX_FN_THROWS: u32 = 8;
40
/// Maximum number of variants in a union.
41
/// Nb. This should not be raised above `255`,
42
/// as tags are stored using 8-bits only.
43
export constant MAX_UNION_VARIANTS: u32 = 128;
44
/// Maximum nesting of loops.
45
export constant MAX_LOOP_DEPTH: u32 = 16;
46
/// Maximum trait instances.
47
export constant MAX_INSTANCES: u32 = 128;
48
/// Maximum standalone methods (across all types).
49
export constant MAX_METHODS: u32 = 256;
50
/// Maximum number of linear bindings active in one function.
51
constant MAX_LINEAR_BINDINGS: u32 = 32;
52
/// Maximum full-region projections active in nested lexical regions.
53
constant MAX_REGIONAL_LOANS: u32 = 32;
54
/// Maximum inline field depth used to prove borrow separation.
55
constant MAX_BORROW_FIELDS: u32 = 16;
56
/// Maximum nesting depth tracked for loops.
57
constant MAX_LINEAR_LOOP_DEPTH: u32 = 16;
58
59
/// Trait definition stored in the resolver.
60
export record TraitType: Copy {
61
    /// Trait name.
62
    name: *[u8],
63
    /// Module that declares the trait.
64
    moduleId: u16,
65
    /// Method signatures, including from supertraits.
66
    methods: *unsafe mut [TraitMethod],
67
    /// Supertraits that must also be implemented.
68
    supertraits: *unsafe mut [*unsafe TraitType],
69
}
70
71
/// A single method signature within a trait.
72
export record TraitMethod: Copy {
73
    /// Method name.
74
    name: *[u8],
75
    /// Function type for the method, excluding the receiver.
76
    fnType: *FnType,
77
    /// Whether the receiver is mutable.
78
    mutable: bool,
79
    /// Pointer-like class used by the receiver.
80
    receiverClass: types::PointerClass,
81
    /// V-table slot index.
82
    index: u32,
83
}
84
85
/// An entry in the trait instance registry.
86
export record InstanceEntry: Copy {
87
    /// Trait type descriptor.
88
    traitType: *unsafe TraitType,
89
    /// Concrete type that implements the trait.
90
    concreteType: Type,
91
    /// Name of the concrete type.
92
    concreteTypeName: *[u8],
93
    /// Module where this instance was declared.
94
    moduleId: u16,
95
    /// Method symbols for each trait method, in declaration order.
96
    methods: *unsafe mut [*unsafe mut Symbol],
97
}
98
99
/// An entry in the method registry.
100
export record MethodEntry: Copy {
101
    /// Concrete type that owns the method.
102
    concreteType: Type,
103
    /// Name of the concrete type.
104
    concreteTypeName: *[u8],
105
    /// Method name.
106
    name: *[u8],
107
    /// Function type excluding the receiver.
108
    fnType: *FnType,
109
    /// Whether the receiver is mutable.
110
    mutable: bool,
111
    /// Pointer-like class used by the receiver.
112
    receiverClass: types::PointerClass,
113
    /// Symbol for the method.
114
    symbol: *unsafe mut Symbol,
115
}
116
117
/// Identifier for the synthetic `len` field.
118
export constant LEN_FIELD: *[u8] = "len";
119
/// Identifier for the synthetic `ptr` field.
120
export constant PTR_FIELD: *[u8] = "ptr";
121
/// Identifier for the synthetic `cap` field.
122
export constant CAP_FIELD: *[u8] = "cap";
123
124
/// Maximum `u16` value.
125
constant U16_MAX: u16 = 0xFFFF;
126
/// Maximum `u8` value.
127
constant U8_MAX: u16 = 0xFF;
128
129
/// Minimum `i8` value.
130
constant I8_MIN: i32 = -128;
131
/// Maximum `i8` value.
132
constant I8_MAX: i32 = 127;
133
/// Minimum `i16` value.
134
constant I16_MIN: i32 = -32768;
135
/// Maximum `i16` value.
136
constant I16_MAX: i32 = 32767;
137
138
/// Minimum `i32` value.
139
constant I32_MIN: i32 = -2147483648;
140
/// Maximum `i32` value.
141
constant I32_MAX: i32 = 2147483647;
142
/// Minimum `i64` value: -(2^63).
143
constant I64_MIN: i64 = -9223372036854775808;
144
/// Maximum `i64` value: 2^63 - 1.
145
constant I64_MAX: i64 = 9223372036854775807;
146
147
/// Size of a pointer in bytes.
148
export constant PTR_SIZE: u32 = 8;
149
150
/// Information about a record or tuple field.
151
export record RecordField: Copy {
152
    /// Field name, `nil` for positional fields.
153
    name: ?*[u8],
154
    /// Field type.
155
    fieldType: Type,
156
    /// Byte offset from the start of the record.
157
    offset: i32,
158
}
159
160
/// Information about a union variant.
161
record UnionVariant: Copy {
162
    name: *[u8],
163
    valueType: Type,
164
    symbol: *unsafe mut Symbol,
165
}
166
167
/// Array type payload.
168
export record ArrayType: Copy {
169
    item: *Type,
170
    length: u32,
171
}
172
173
/// Record nominal type.
174
export record RecordType: Copy {
175
    /// Region parameters of the source declaration.
176
    regions: ?*RegionScope,
177
    /// Exact region arguments, if this is an applied type.
178
    application: ?*unsafe NominalApplication,
179
    fields: *unsafe [RecordField],
180
    labeled: bool,
181
    /// Shared layout of the source declaration.
182
    layout: *Layout,
183
    /// Whether the declaration explicitly carries the `Once` marker.
184
    declaredLinear: bool,
185
    /// Whether the declaration explicitly carries the `Copy` marker.
186
    declaredCopy: bool,
187
}
188
189
/// Union nominal type.
190
export record UnionType: Copy {
191
    /// Region parameters of the source declaration.
192
    regions: ?*RegionScope,
193
    /// Exact region arguments, if this is an applied type.
194
    application: ?*unsafe NominalApplication,
195
    variants: *unsafe [UnionVariant],
196
    /// Shared layout of the source declaration.
197
    layout: *Layout,
198
    /// Cached payload offset within the union aggregate.
199
    valOffset: u32,
200
    /// If all variants have void payloads.
201
    isAllVoid: bool,
202
    /// Whether the declaration explicitly carries the `Once` marker.
203
    declaredLinear: bool,
204
    /// Whether the declaration explicitly carries the `Copy` marker.
205
    declaredCopy: bool,
206
}
207
208
/// Metadata for user-defined types.
209
export union NominalType: Copy {
210
    /// Placeholder for a type that hasn't been fully resolved yet.
211
    /// Stores the declaration node for lazy resolution.
212
    Placeholder(*ast::Node),
213
    /// Declaration whose value layout is under analysis.
214
    Resolving(*ast::Node),
215
    /// Applied type whose field or variant view is not yet resolved.
216
    Application(*unsafe NominalApplication),
217
    Record(RecordType),
218
    Union(UnionType),
219
}
220
221
/// Coercion plan, when coercion from one type to another.
222
export union Coercion: Copy {
223
    /// No coercion, eg. `T -> T`.
224
    Identity,
225
    /// Eg. `u8 -> i32`. Stores both source and target types for lowering.
226
    NumericCast { from: Type, to: Type },
227
    /// Eg. `T -> ?T`. Stores the inner value type.
228
    OptionalLift(Type),
229
    /// Wrap return value in success variant of result type.
230
    ResultWrap,
231
    /// Coerce a concrete pointer to a trait object.
232
    TraitObject {
233
        /// Trait type information.
234
        traitInfo: *unsafe TraitType,
235
        /// Instance entry for v-table lookup.
236
        inst: *unsafe InstanceEntry,
237
    },
238
}
239
240
/// Result of resolving a module path.
241
record ResolvedModule: Copy {
242
    /// Module entry in the graph.
243
    entry: *module::ModuleEntry,
244
    /// Scope containing the module's declarations.
245
    scope: *unsafe mut Scope,
246
}
247
248
/// Type layout.
249
export record Layout: Copy {
250
    /// Size in bytes.
251
    size: u32,
252
    /// Alignment in bytes.
253
    alignment: u32,
254
}
255
256
/// Computed union layout parameters.
257
record UnionLayoutInfo: Copy {
258
    layout: Layout,
259
    valOffset: u32,
260
    isAllVoid: bool,
261
}
262
263
/// Pre-computed metadata for slice range expressions.
264
/// Used by the lowerer.
265
export record SliceRangeInfo: Copy {
266
    /// Element type of the resulting slice.
267
    itemType: *Type,
268
    /// Whether the resulting slice is mutable.
269
    mutable: bool,
270
    /// Static capacity if container is an array.
271
    capacity: ?u32,
272
}
273
274
/// Pre-computed metadata for `for` loop iteration.
275
/// Used by the lowerer to avoid re-analyzing the iterable type.
276
export union ForLoopInfo: Copy {
277
    /// Iterating over a range expression (e.g., `for i in 0..n`).
278
    Range {
279
        valType: *Type,
280
        range: ast::Range,
281
        bindingName: ?*[u8],
282
        indexName: ?*[u8]
283
    },
284
    /// Iterating over an array or slice. For arrays, the length field is set.
285
    Collection {
286
        elemType: *Type,
287
        length: ?u32,
288
        bindingName: ?*[u8],
289
        indexName: ?*[u8]
290
    },
291
}
292
293
/// Resolved function signature details.
294
export record FnType: Copy {
295
    /// Symbolic regions declared by the source function.
296
    regions: ?*RegionScope,
297
    /// Parameter types in call order.
298
    paramTypes: *[*Type],
299
    /// Return value type.
300
    returnType: *Type,
301
    /// Error types that the function can throw.
302
    throwList: *[*Type],
303
    /// Whether calling this function requires an unsafe context.
304
    isUnsafe: bool,
305
}
306
307
/// Describes a type computed during semantic analysis.
308
export union Type: Copy {
309
    /// A type that couldn't be decided.
310
    Unknown,
311
    /// Types only used during inference.
312
    Nil, Undefined, Int,
313
    /// Primitive types.
314
    Void, Opaque, Never, Bool,
315
    /// Integer types.
316
    U8, U16, U32, U64, I8, I16, I32, I64,
317
    /// Shared cell pointer with value access to a Copy payload.
318
    Cell {
319
        /// Storage lifetime and ownership class.
320
        class: types::PointerClass,
321
        /// Payload type, preserved by all writes.
322
        payload: *Type,
323
    },
324
    /// Affine allocation interface retained by a lexical region.
325
    Session(*unsafe types::Region),
326
    /// Range types, eg. `start..end`.
327
    Range {
328
        start: ?*Type,
329
        end: ?*Type,
330
    },
331
    /// Owning pointer-like address.
332
    Pointer {
333
        class: types::PointerClass,
334
        target: *Type,
335
        mutable: bool,
336
    },
337
    /// Owning slice.
338
    Slice {
339
        class: types::PointerClass,
340
        item: *Type,
341
        mutable: bool,
342
    },
343
    /// Eg. `[i32; 32]`.
344
    Array(ArrayType),
345
    /// Eg. `?T`.
346
    Optional(*Type),
347
    /// Eg. `fn id(i32) -> i32`.
348
    Fn(*FnType),
349
    /// Named, ie. user-defined types, includes union variants.
350
    Nominal(*unsafe NominalType),
351
    /// Owning trait object. An erased type with v-table.
352
    TraitObject {
353
        /// Ownership and safety class.
354
        class: types::PointerClass,
355
        /// Trait definition.
356
        traitInfo: *unsafe TraitType,
357
        /// Whether the pointer is mutable.
358
        mutable: bool,
359
    },
360
}
361
362
/// Structured diagnostic payload for type mismatches.
363
export record TypeMismatch: Copy {
364
    expected: Type,
365
    actual: Type,
366
}
367
368
/// Structured diagnostic payload for invalid `as` casts.
369
export record InvalidAsCast: Copy {
370
    from: Type,
371
    to: Type,
372
}
373
374
/// Diagnostic payload for argument count mismatches.
375
export record CountMismatch: Copy {
376
    expected: u32,
377
    actual: u32,
378
}
379
380
/// Detailed payload attached to a symbol, specialized per symbol kind.
381
export union SymbolData: Copy {
382
    /// Payload describing mutable bindings like variables or functions.
383
    Value {
384
        /// Whether the binding permits mutation.
385
        mutable: bool,
386
        /// Custom alignment requirement, or 0 for default.
387
        alignment: u32,
388
        /// Resolved type associated with the value.
389
        type: Type,
390
        /// Whether the variable's address is taken anywhere (via `&` or `&mut`).
391
        /// Used by the lowerer to allocate a stack slot eagerly.
392
        addressTaken: bool,
393
    },
394
    /// Payload describing constants.
395
    Constant {
396
        /// Resolved type associated with the value.
397
        type: Type,
398
        /// Constant value, if any.
399
        value: ?ConstValue,
400
    },
401
    /// Payload describing union variants and the union type they instantiate.
402
    Variant {
403
        /// Variant payload type.
404
        type: Type,
405
        /// Union declaration.
406
        decl: *ast::Node,
407
        /// Variant ordinal in declaration order.
408
        ordinal: u32,
409
        /// Variant index within the union.
410
        index: u32,
411
    },
412
    /// Module reference.
413
    Module {
414
        /// Module entry in the graph.
415
        entry: *module::ModuleEntry,
416
        /// Module scope.
417
        scope: *unsafe mut Scope,
418
    },
419
    /// Payload describing type symbols with their resolved type.
420
    Type(*unsafe mut NominalType),
421
    /// Trait symbol.
422
    Trait(*unsafe mut TraitType),
423
}
424
425
/// Resolved symbol allocated during semantic analysis.
426
export record Symbol: Copy {
427
    /// Symbol name in source code.
428
    name: *[u8],
429
    /// Data associated with the symbol.
430
    data: SymbolData,
431
    /// Bitset of attributes applied to the declaration.
432
    attrs: u32,
433
    /// AST node that introduced the symbol.
434
    node: *ast::Node,
435
    /// Module ID this symbol belongs to. Only for module-level symbols.
436
    moduleId: ?u16,
437
}
438
439
/// Integer constant payload.
440
export record ConstInt: Copy {
441
    /// Absolute magnitude of the value.
442
    magnitude: u64,
443
    /// Bit width of the integer.
444
    bits: u8,
445
    /// Whether the integer is signed.
446
    signed: bool,
447
    /// Whether the value is negative (only valid when `signed` is true).
448
    negative: bool,
449
}
450
451
/// Constant value recorded for literal nodes.
452
export union ConstValue: Copy {
453
    Bool(bool),
454
    Char(u8),
455
    String(*[u8]),
456
    Int(ConstInt),
457
}
458
459
/// Integer range metadata for primitive integer types.
460
union IntegerRange: Copy {
461
    Signed {
462
        bits: u8,
463
        min: i64,
464
        max: i64,
465
        lim: u64,
466
    },
467
    Unsigned {
468
        bits: u8,
469
        max: u64,
470
    },
471
}
472
473
/// Diagnostic emitted by the analyzer.
474
export record Error: Copy {
475
    /// Error category.
476
    kind: ErrorKind,
477
    /// Node associated with the error, if known.
478
    node: ?*ast::Node,
479
    /// Module ID where this error occurred.
480
    moduleId: u16,
481
}
482
483
/// High-level classification for semantic diagnostics.
484
export union ErrorKind: Copy {
485
    /// Identifier declared more than once in the same scope.
486
    DuplicateBinding(*[u8]),
487
    /// Identifier referenced before it was declared.
488
    UnresolvedSymbol(*[u8]),
489
    /// Attempted to assign to an immutable binding.
490
    ImmutableBinding,
491
    /// Slice append requires a valid allocator record and callback.
492
    InvalidSliceAllocator,
493
    /// Expected a compile-time constant expression.
494
    ConstExprRequired,
495
    /// Symbol arena exhausted while binding identifiers.
496
    SymbolOverflow,
497
    /// Expression has the wrong type.
498
    TypeMismatch(TypeMismatch),
499
    /// Numeric literal does not fit within the required range.
500
    NumericLiteralOverflow,
501
    /// Record literal omitted a required field.
502
    RecordFieldMissing(*[u8]),
503
    /// Record literal referenced a field that does not exist.
504
    RecordFieldUnknown(*[u8]),
505
    /// Brace syntax used on unlabeled record.
506
    RecordFieldStyleMismatch,
507
    /// Record literal supplied the wrong number of fields.
508
    RecordFieldCountMismatch(CountMismatch),
509
    /// Record literal fields not in declaration order.
510
    RecordFieldOutOfOrder { field: *[u8], prev: *[u8] },
511
    /// Function call supplied the wrong number of arguments.
512
    FnArgCountMismatch(CountMismatch),
513
    /// Function throws list has the wrong number of types.
514
    FnThrowCountMismatch(CountMismatch),
515
    /// Expected an identifier node.
516
    ExpectedIdentifier,
517
    /// Expected any optional type.
518
    ExpectedOptional,
519
    /// Expected a numeric type.
520
    ExpectedNumeric,
521
    /// Expected a pointer type.
522
    ExpectedPointer,
523
    /// Expected a record type.
524
    ExpectedRecord,
525
    /// Expected an array or slice value.
526
    ExpectedIndexable,
527
    /// Expected an iterable (array, slice, or range) for a `for` loop.
528
    ExpectedIterable,
529
    /// Invalid `as` cast between the provided types.
530
    InvalidAsCast(InvalidAsCast),
531
    /// Invalid alignment value specified.
532
    InvalidAlignmentValue(u32),
533
    /// Invalid module path.
534
    InvalidModulePath,
535
    /// Invalid identifier.
536
    InvalidIdentifier(*ast::Node),
537
    /// Invalid scope access.
538
    InvalidScopeAccess,
539
    /// Referenced an unknown array field.
540
    ArrayFieldUnknown(*[u8]),
541
    /// Referenced an unknown slice field.
542
    SliceFieldUnknown(*[u8]),
543
    /// Array slicing without taking an address.
544
    SliceRequiresAddress,
545
    /// Slice bounds exceed array length.
546
    SliceRangeOutOfBounds,
547
    /// Unexpected `return` statement.
548
    UnexpectedReturn,
549
    /// Unexpected module name.
550
    UnexpectedModuleName,
551
    /// Unexpected node.
552
    UnexpectedNode(*ast::Node),
553
    /// Function with non-void return type falls through without returning.
554
    FnMissingReturn,
555
    /// Function is missing a body.
556
    FnMissingBody,
557
    /// Function body is not expected.
558
    FnUnexpectedBody,
559
    /// Intrinsic function must not have a body.
560
    IntrinsicUnexpectedBody,
561
    /// Encountered loop control outside of a loop construct.
562
    InvalidLoopControl,
563
    /// `try` used when the enclosing function does not declare throws.
564
    TryRequiresThrows,
565
    /// `try` used to propagate an error not declared by the enclosing function.
566
    TryIncompatibleError,
567
    /// `throw` used when the enclosing function does not declare throws.
568
    ThrowRequiresThrows,
569
    /// `throw` used with an error type not declared by the enclosing function.
570
    ThrowIncompatibleError,
571
    /// `try` applied to an expression that cannot throw.
572
    TryNonThrowing,
573
    /// Inferred catch binding used with multi-error callee.
574
    TryCatchMultiError,
575
    /// Duplicate error type in typed catch clauses.
576
    TryCatchDuplicateType,
577
    /// Distinct error types have the same tag after region erasure.
578
    AmbiguousRegionalError,
579
    /// Typed catch clauses do not cover all error types.
580
    TryCatchNonExhaustive,
581
    /// Called a fallible function without using `try`.
582
    MissingTry,
583
    /// Cannot use opaque type in this context.
584
    OpaqueTypeNotAllowed,
585
    /// Cannot dereference pointer to opaque type.
586
    OpaqueTypeDeref,
587
    /// Cannot perform pointer arithmetic on opaque pointer.
588
    OpaquePointerArithmetic,
589
    /// Cannot infer type from context.
590
    CannotInferType,
591
    /// Cannot assign a void value to a variable.
592
    CannotAssignVoid,
593
    /// `default` attribute used on a non-function declaration.
594
    DefaultAttrOnlyOnFn,
595
    /// Union variant requires a payload but none was provided.
596
    UnionVariantPayloadMissing(*[u8]),
597
    /// Union variant does not expect a payload but one was provided.
598
    UnionVariantPayloadUnexpected(*[u8]),
599
    /// `match` on a union omits a variant without a `default` case.
600
    UnionMatchNonExhaustive(*[u8]),
601
    /// `match` on an optional is missing a value case.
602
    OptionalMatchMissingValue,
603
    /// `match` on an optional is missing a nil case.
604
    OptionalMatchMissingNil,
605
    /// `match` on a bool is missing a case (true or false).
606
    BoolMatchMissing(bool),
607
    /// `match` on a non-union type is missing a catch-all.
608
    MatchNonExhaustive,
609
    /// `match` has more than one catch-all prongs.
610
    DuplicateCatchAll,
611
    /// `match` has a duplicate case pattern.
612
    DuplicateMatchPattern,
613
    /// `match` has an unreachable `else`: all cases are already handled.
614
    UnreachableElse,
615
    /// Builtin called with wrong number of arguments.
616
    BuiltinArgCountMismatch(CountMismatch),
617
    /// Instance method receiver mutability does not match the trait declaration.
618
    ReceiverMutabilityMismatch,
619
    /// Duplicate instance declaration for the same (trait, type) pair.
620
    DuplicateInstance,
621
    /// Instance declaration is missing a required trait method.
622
    MissingTraitMethod(*[u8]),
623
    /// Trait name used as a value expression.
624
    UnexpectedTraitName,
625
    /// Trait method receiver does not point to the declaring trait.
626
    TraitReceiverMismatch,
627
    /// Trait declaration and instance disagree about unsafe call requirements.
628
    TraitMethodSafetyMismatch,
629
    /// Function declaration has too many parameters.
630
    FnParamOverflow(CountMismatch),
631
    /// Function declaration has too many throws.
632
    FnThrowOverflow(CountMismatch),
633
    /// Trait declaration has too many methods.
634
    TraitMethodOverflow(CountMismatch),
635
    /// Instance declaration is missing a required supertrait instance.
636
    MissingSupertraitInstance(*[u8]),
637
    /// An affine binding was used after it moved.
638
    AffineUseAfterMove(*[u8]),
639
    /// Linear binding was consumed more than once.
640
    LinearUseAfterConsume(*[u8]),
641
    /// Linear binding remains available at an exit.
642
    LinearNotConsumed(*[u8]),
643
    /// A case-pattern `let-else` fallback must terminate control flow.
644
    LinearLetElseMustTerminate,
645
    /// Branches disagree about a linear binding's state.
646
    LinearBranchMismatch(*[u8]),
647
    /// A linear field cannot be moved independently.
648
    LinearPartialMove,
649
    /// A linear value cannot be discarded.
650
    LinearDiscard,
651
    /// Assignment would overwrite a live linear value.
652
    LinearOverwrite,
653
    /// `undefined` cannot initialize a linear type.
654
    LinearUndefined,
655
    /// A `Copy` declaration contains a non-copy field or variant.
656
    CopyContainsNonCopy,
657
    /// A declaration carries both `Copy` and `Once`.
658
    ConflictingOwnershipMarkers,
659
    /// A region name is not visible in this declaration or block.
660
    UnknownRegion(*[u8]),
661
    /// A region application has the wrong argument count.
662
    RegionArgumentCount(CountMismatch),
663
    /// A region parameter has no consistent argument from checked references.
664
    RegionInference(*[u8]),
665
    /// A region argument does not satisfy its declared parent relation.
666
    RegionParent(*[u8]),
667
    /// A region parent relation contains a cycle.
668
    RegionCycle(*[u8]),
669
    /// A value retains a region that has left lexical scope.
670
    RegionEscape(*[u8]),
671
    /// A session requires one exclusive borrow of an allocation trait implementer.
672
    InvalidSessionSource,
673
    /// Allocation requires a value that can be discarded without destruction.
674
    InvalidAllocationValue,
675
    /// Cell payload is not a storable plain Copy value.
676
    InvalidCellPayload,
677
    /// The allocated value has an invalid or overflowing layout.
678
    InvalidAllocationLayout,
679
    /// A compiler-known allocation trait method has an invalid signature.
680
    InvalidAllocationRuntime,
681
    /// The function has too many distinct full-region projections.
682
    RegionalLoanOverflow,
683
    /// A nominal value layout contains itself.
684
    RecursiveType,
685
    /// A reference appears in a storable or escaping position.
686
    InvalidRefPosition,
687
    /// A reference local requires a fixed binding to existing storage.
688
    RefBinding,
689
    /// Call arguments contain overlapping incompatible loans.
690
    BorrowConflict(*[u8]),
691
    /// Unsafe operation outside an unsafe context.
692
    UnsafeOperation,
693
    /// An unsafe call requires an unsafe context.
694
    UnsafeCall,
695
    /// Internal error.
696
    Internal,
697
}
698
699
/// Diagnostics returned by the analyzer.
700
export record Diagnostics: Copy {
701
    /// Immutable errors captured at the end of an analysis operation.
702
    errors: *[Error],
703
}
704
705
/// Mutable diagnostic storage owned by a resolver.
706
record DiagnosticBuffer {
707
    /// Backing entries. Only the prefix below `len` is initialized.
708
    entries: *mut [Error],
709
    /// Number of recorded errors.
710
    len: u32,
711
}
712
713
/// Call context.
714
union CallCtx: Copy {
715
    /// Normal function call.
716
    Normal,
717
    /// Fallible function call, ie. `try f()`.
718
    Try,
719
}
720
721
/// Result of resolving a record literal's type name.
722
record ResolvedRecordLitType: Copy {
723
    /// The record nominal type to use for field checking.
724
    recordType: *unsafe NominalType,
725
    /// The result type of the literal (record type or union type for variants).
726
    resultType: Type,
727
}
728
729
/// Result of checking for a `super` path prefix.
730
record SuperAccessResult: Copy {
731
    scope: *unsafe mut Scope,
732
    child: *ast::Node,
733
}
734
735
/// Initialization operation performed after session storage reservation.
736
export union SessionAllocationKind: Copy {
737
    /// Initialize one object from a value.
738
    New,
739
    /// Copy plain Copy elements from a slice.
740
    Copy,
741
    /// Fill a slice with a plain Copy value.
742
    Fill,
743
}
744
745
/// Typed session allocation and its checked runtime reservation function.
746
export record SessionAllocation: Copy {
747
    /// Initialization operation.
748
    kind: SessionAllocationKind,
749
    /// Initialized element type.
750
    item: *Type,
751
    /// Allocation trait used by the session source.
752
    traitInfo: *unsafe TraitType,
753
    /// Reservation method slot in the allocation trait.
754
    methodIndex: u32,
755
}
756
757
/// Node-specific resolver metadata.
758
export union NodeExtra: Copy {
759
    /// No extra data for this node.
760
    None,
761
    /// Region identities owned by a source declaration.
762
    Regions(*RegionScope),
763
    /// Resolved field index for record literal fields.
764
    RecordField { index: u32 },
765
    /// Slice range metadata for subscript expressions with ranges.
766
    SliceRange(SliceRangeInfo),
767
    /// Cached union variant metadata for patterns/constructors.
768
    UnionVariant { ordinal: u32, tag: u32 },
769
    /// Match prong metadata.
770
    MatchProng { catchAll: bool },
771
    /// Match expression metadata.
772
    Match { isConst: bool },
773
    /// For-loop iteration metadata.
774
    ForLoop(ForLoopInfo),
775
    /// Trait method call metadata.
776
    TraitMethodCall {
777
        /// Trait definition.
778
        traitInfo: *unsafe TraitType,
779
        /// Method index in the v-table.
780
        methodIndex: u32,
781
    },
782
    /// Standalone method call metadata.
783
    MethodCall { method: *unsafe MethodEntry },
784
    /// Typed allocation through a session interface.
785
    SessionAllocation(SessionAllocation),
786
    /// Slice `.append(val, allocator)` method call.
787
    SliceAppend { elemType: *Type },
788
    /// Slice `.delete(index)` method call.
789
    SliceDelete { elemType: *Type },
790
}
791
792
/// Combined resolver metadata for a single AST node.
793
export record NodeData: Copy {
794
    /// Number of local bindings and internal iteration variables in this function.
795
    localCount: u32,
796
    /// Resolved type for this node.
797
    ty: Type,
798
    /// Coercion plan applied to this node.
799
    coercion: Coercion,
800
    /// Symbol associated with this node.
801
    sym: ?*unsafe mut Symbol,
802
    /// Constant value for literal nodes.
803
    constValue: ?ConstValue,
804
    /// Lexical scope owned by this node.
805
    scope: ?*unsafe mut Scope,
806
    /// Node-specific extra data.
807
    extra: NodeExtra,
808
}
809
810
/// Table storing all resolver metadata indexed by node ID.
811
record NodeDataTable {
812
    /// Semantic data indexed by AST node ID.
813
    entries: *mut [NodeData],
814
}
815
816
/// Lexical scope.
817
export record Scope: Copy {
818
    /// Owning AST node, or `nil` for the root scope.
819
    owner: ?*ast::Node,
820
    /// Parent/enclosing scope.
821
    parent: ?*unsafe mut Scope,
822
    /// Module ID if this is a module scope.
823
    moduleId: ?u16,
824
    /// Symbols introduced inside the scope, allocated from the arena.
825
    symbols: *unsafe mut [*unsafe mut Symbol],
826
    /// Number of live symbols.
827
    symbolsLen: u32,
828
}
829
830
/// An object used by the enter and exit functions for module scopes.
831
record ModuleScope: Copy {
832
    /// Module root node.
833
    root: *ast::Node,
834
    /// Module entry in graph.
835
    entry: *module::ModuleEntry,
836
    /// The newly entered scope.
837
    newScope: *unsafe mut Scope,
838
    /// The previous scope.
839
    prevScope: *unsafe mut Scope,
840
    /// The previous module.
841
    prevMod: u16,
842
}
843
844
/// Loop context for tracking control flow within loops.
845
record LoopCtx: Copy {
846
    /// Whether a reachable break was encountered in this loop.
847
    /// This is used to determine whether a loop diverges.
848
    hasBreak: bool,
849
}
850
851
/// Configuration for semantic analysis.
852
export record Config: Copy {
853
    /// Whether we're building in test mode.
854
    buildTest: bool,
855
}
856
857
/// How pattern bindings are created during match.
858
export union MatchBy: Copy {
859
    /// Match by value.
860
    Value,
861
    /// Match by immutable reference.
862
    Ref,
863
    /// Match by mutable reference.
864
    MutRef,
865
}
866
867
/// State of a match statement being resolved.
868
// TODO: This is only used because of the maximum function param limitation.
869
record MatchState: Copy {
870
    /// Is the match catch-all?
871
    catchAll: bool,
872
    /// Is the match constant?
873
    isConst: bool
874
}
875
876
/// Result of unwrapping a type for pattern matching.
877
export record MatchSubject: Copy {
878
    /// The effective type to match against.
879
    effectiveTy: Type,
880
    /// How bindings should be created.
881
    by: MatchBy,
882
}
883
884
/// How an expression uses a linear result.
885
union LinearUse: Copy {
886
    /// Consume the value and end its availability.
887
    Consume,
888
    /// Read the value without consuming it.
889
    Observe,
890
    /// Borrow the value through a reference.
891
    Borrow,
892
    /// Discard an unused expression result.
893
    Discard,
894
    /// Use the value as an assignment target.
895
    Place,
896
    /// Evaluate a place prefix after checking the complete place.
897
    Locate,
898
}
899
900
/// Per-control-flow-path ownership state.
901
/// Read only the initialized symbol prefix below `len`.
902
record LinearEnv: Copy {
903
    /// Active full-region loans, indexed by the checker's regional loan table.
904
    regionalLoans: u64,
905
    /// Symbol pointers. Entries below `len` are initialized and not optional.
906
    symbols: [*unsafe mut Symbol; MAX_LINEAR_BINDINGS],
907
    /// Bit set for each binding that remains available.
908
    available: u64,
909
    /// Number of initialized entries in `symbols`.
910
    len: u32,
911
    /// Whether this control-flow path has terminated.
912
    terminated: bool,
913
}
914
915
/// A storage root and its statically distinct record fields.
916
record BorrowPlace: Copy {
917
    /// Symbol that owns or supplies the storage.
918
    root: ?*unsafe mut Symbol,
919
    /// Field indices before the first uncertain projection.
920
    fields: [u32; MAX_BORROW_FIELDS],
921
    /// Number of initialized field indices.
922
    len: u32,
923
    /// Whether further projections can identify distinct storage.
924
    precise: bool,
925
}
926
927
/// A reference binding that protects its source for one lexical scope.
928
record LocalLoan: Copy {
929
    /// Local symbol through which the source can be accessed.
930
    binding: *unsafe mut Symbol,
931
    /// Storage retained by the reference.
932
    place: BorrowPlace,
933
    /// Whether other reads of the source are excluded.
934
    exclusive: bool,
935
}
936
937
/// Function-local exact-use checker state.
938
/// Read loop arrays only at indices below `loopDepth`.
939
/// `enterLinearLoop` initializes each slot before it increases `loopDepth`.
940
record LinearChecker: 'arena + 'checking where 'arena: 'checking {
941
    /// Resolver that owns the symbols and diagnostics.
942
    resolver: &'checking mut Resolver 'arena,
943
    /// Regional projections discovered in this function.
944
    regional: [RegionalLoan; MAX_REGIONAL_LOANS],
945
    /// Number of initialized regional loan entries.
946
    regionalLen: u32,
947
    /// Named regions active at the current source location.
948
    regions: ?*RegionScope,
949
    /// Regional loans carried to each loop's next iteration.
950
    loopBackLoans: [u64; MAX_LINEAR_LOOP_DEPTH],
951
    /// Regional loans carried to each loop's exits.
952
    loopExitLoans: [u64; MAX_LINEAR_LOOP_DEPTH],
953
    /// Regions active at each loop's entry and exit.
954
    loopRegions: [?*RegionScope; MAX_LINEAR_LOOP_DEPTH],
955
    /// Source places protected by active pattern references.
956
    loans: [BorrowPlace; MAX_LINEAR_BINDINGS],
957
    /// Number of initialized entries in `loans`.
958
    loanLen: u32,
959
    /// Reference locals in active lexical scopes.
960
    locals: [LocalLoan; MAX_LINEAR_BINDINGS],
961
    /// Number of initialized local loans.
962
    localLen: u32,
963
    /// Binding count at entry to each active loop.
964
    loopMarks: [u32; MAX_LINEAR_LOOP_DEPTH],
965
    /// Available bindings at entry to each active loop.
966
    loopAvailable: [u64; MAX_LINEAR_LOOP_DEPTH],
967
    /// Available bindings shared by the exits from each active loop.
968
    loopExitAvailable: [u64; MAX_LINEAR_LOOP_DEPTH],
969
    /// Whether each active loop can exit without `break`.
970
    loopHasNaturalExit: [bool; MAX_LINEAR_LOOP_DEPTH],
971
    /// Whether each active loop contains a reachable `break`.
972
    loopBreakSeen: [bool; MAX_LINEAR_LOOP_DEPTH],
973
    /// Number of active loops.
974
    loopDepth: u32,
975
}
976
977
/// Unwrap a pointer type for pattern matching.
978
export fn unwrapMatchSubject(ty: Type) -> MatchSubject {
979
    if let case Type::Pointer { target, mutable, .. } = ty {
980
        let by = MatchBy::MutRef if mutable else MatchBy::Ref;
981
        return MatchSubject { effectiveTy: *target, by };
982
    }
983
    return MatchSubject { effectiveTy: ty, by: MatchBy::Value };
984
}
985
986
/// Region names introduced by a declaration or lexical block.
987
export record RegionScope: Copy {
988
    /// Entries in declaration order.
989
    entries: *unsafe [*unsafe mut types::Region],
990
    /// Enclosing lexical region environment.
991
    parent: ?*RegionScope,
992
}
993
994
/// Region arguments for one source declaration.
995
record RegionSubstitution: Copy {
996
    /// Declared parameters in source order.
997
    parameters: *RegionScope,
998
    /// Inferred or explicit arguments. Every entry must be set before substitution.
999
    arguments: *unsafe mut [?*unsafe types::Region],
1000
}
1001
1002
/// One interned application of a nominal declaration to exact region arguments.
1003
export record NominalApplication: Copy {
1004
    /// Canonical source declaration identity.
1005
    base: *unsafe NominalType,
1006
    /// Source parameters in declaration order.
1007
    parameters: *RegionScope,
1008
    /// Region arguments in parameter order.
1009
    arguments: *unsafe [*unsafe types::Region],
1010
    /// Stable descriptor for the substituted field or variant view.
1011
    view: *unsafe mut NominalType,
1012
    /// Next application in the resolver cache.
1013
    next: ?*unsafe NominalApplication,
1014
}
1015
1016
/// Global resolver state.
1017
export record Resolver: 'arena {
1018
    /// Active region names for source type checking.
1019
    regionScope: ?*RegionScope,
1020
    /// Interned applications of nominal region parameters.
1021
    applications: ?*unsafe NominalApplication,
1022
    /// Current scope.
1023
    scope: *unsafe mut Scope,
1024
    /// Package scope containing package roots and top-level symbols.
1025
    pkgScope: *unsafe mut Scope,
1026
    /// Stack of loop contexts for nested loops.
1027
    loopStack: [LoopCtx; MAX_LOOP_DEPTH],
1028
    /// Current loop depth, indexes into loop stack.
1029
    loopDepth: u32,
1030
    /// Signature of the function currently being analyzed.
1031
    currentFn: ?FnType,
1032
    /// Declaration that owns the active function body and its local bindings.
1033
    currentFnNode: ?*ast::Node,
1034
    /// Current module being analyzed.
1035
    currentMod: u16,
1036
    /// Whether the current lexical context permits unsafe operations.
1037
    inUnsafeContext: bool,
1038
    /// Configuration for semantic analysis.
1039
    config: Config,
1040
    /// Caller-owned arena, valid for this resolver and all emitted metadata.
1041
    arena: &'arena mut alloc::Arena,
1042
    /// Combined semantic metadata table indexed by node ID.
1043
    nodeData: NodeDataTable,
1044
    /// Linked list of interned types.
1045
    types: ?*TypeNode,
1046
    /// Diagnostics recorded so far.
1047
    errors: DiagnosticBuffer,
1048
    /// Module graph for the current package.
1049
    moduleGraph: *unsafe module::ModuleGraph,
1050
    /// Cache of module scopes indexed by module ID.
1051
    moduleScopes: [?*unsafe mut Scope; module::MAX_MODULES],
1052
    /// Trait instance registry.
1053
    instances: [InstanceEntry; MAX_INSTANCES],
1054
    /// Number of registered instances.
1055
    instancesLen: u32,
1056
    /// Standalone method registry.
1057
    methods: [MethodEntry; MAX_METHODS],
1058
    /// Number of registered standalone methods.
1059
    methodsLen: u32,
1060
}
1061
1062
/// Internal error sentinel thrown when analysis cannot proceed.
1063
export union ResolveError: Copy {
1064
    Failure,
1065
}
1066
1067
/// Node in the type interning linked list.
1068
record TypeNode: Copy {
1069
    ty: Type,
1070
    next: ?*TypeNode,
1071
}
1072
1073
/// Look up a region name in a lexical environment.
1074
unsafe fn findRegion(scope: ?*RegionScope, name: *[u8]) -> ?*unsafe mut types::Region {
1075
    let mut current = scope;
1076
    while let env = current {
1077
        for region in env.entries {
1078
            if mem::eq(region.name, name) {
1079
                return region;
1080
            }
1081
        }
1082
        set current = env.parent;
1083
    }
1084
    return nil;
1085
}
1086
1087
/// Resolve a source region name without using its spelling as an identity.
1088
unsafe fn resolveRegion 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> *unsafe types::Region
1089
    throws (ResolveError)
1090
{
1091
    let case ast::NodeValue::Region { name, .. } = node.value
1092
        else panic "resolveRegion: invalid region node";
1093
    let region = findRegion(self.regionScope, name)
1094
        else throw emitError(self, node, ErrorKind::UnknownRegion(name));
1095
    return region;
1096
}
1097
1098
/// Bind all region parameters before resolving their parent relations.
1099
unsafe fn bindRegions 'arena (self: &mut Resolver 'arena, owner: *ast::Node, nodes: *[*ast::Node]) -> ?*RegionScope
1100
    throws (ResolveError)
1101
{
1102
    if let case NodeExtra::Regions(scope) = self.nodeData.entries[owner.id].extra {
1103
        return scope;
1104
    }
1105
    let mut count: u32 = 0;
1106
    for node in nodes {
1107
        if let case ast::NodeValue::Region { .. } = node.value {
1108
            set count += 1;
1109
        }
1110
    }
1111
    if count == 0 {
1112
        return nil;
1113
    }
1114
    let entries = try! alloc::allocRawSlice(
1115
        self.arena, @sizeOf(*unsafe mut types::Region), @alignOf(*unsafe mut types::Region), count
1116
    ) as *unsafe mut [*unsafe mut types::Region];
1117
    let mut index: u32 = 0;
1118
    for node in nodes {
1119
        let case ast::NodeValue::Region { name, .. } = node.value else continue;
1120
        for i in 0..index {
1121
            if mem::eq(entries[i].name, name) {
1122
                throw emitError(self, node, ErrorKind::DuplicateBinding(name));
1123
            }
1124
        }
1125
        let region = try! alloc::allocRaw(self.arena, @sizeOf(types::Region), @alignOf(types::Region))
1126
            as *unsafe mut types::Region;
1127
        set *region = types::Region { id: node.id, origin: types::RegionOrigin::Parameter, name, parent: nil };
1128
        set entries[index] = region;
1129
        set index += 1;
1130
    }
1131
    let scope = try! alloc::alloc(&mut *self.arena, @sizeOf(RegionScope), @alignOf(RegionScope)) as *mut RegionScope;
1132
    set *scope = RegionScope { entries, parent: nil };
1133
    let frozen: *RegionScope = scope;
1134
    set index = 0;
1135
    for node in nodes {
1136
        let case ast::NodeValue::Region { parent, .. } = node.value else continue;
1137
        if let parentNode = parent {
1138
            let case ast::NodeValue::Region { name, .. } = parentNode.value
1139
                else panic "bindRegions: invalid parent node";
1140
            let target = findRegion(frozen, name)
1141
                else throw emitError(self, parentNode, ErrorKind::UnknownRegion(name));
1142
            if types::regionContains(entries[index], target) {
1143
                throw emitError(self, parentNode, ErrorKind::RegionCycle(entries[index].name));
1144
            }
1145
            set entries[index].parent = target;
1146
        }
1147
        set index += 1;
1148
    }
1149
    set self.nodeData.entries[owner.id].extra = NodeExtra::Regions(frozen);
1150
    return frozen;
1151
}
1152
1153
/// Allocate and intern a type in the arena, returning a pointer for deduplication.
1154
export unsafe fn allocType 'arena (self: &mut Resolver 'arena, ty: Type) -> *Type {
1155
    // Search existing types for a match.
1156
    let mut cursor = self.types;
1157
    while let node = cursor {
1158
        if node.ty == ty {
1159
            return &node.ty;
1160
        }
1161
        set cursor = node.next;
1162
    }
1163
    // Allocate a new type node from the arena.
1164
    let node = try! alloc::alloc(
1165
        &mut *self.arena, @sizeOf(TypeNode), @alignOf(TypeNode)
1166
    ) as *mut TypeNode;
1167
1168
    set *node = TypeNode { ty, next: self.types };
1169
    let frozen: *TypeNode = node;
1170
    set self.types = frozen;
1171
1172
    return &frozen.ty;
1173
}
1174
1175
/// Allocate a nominal type descriptor and return a pointer to it.
1176
unsafe fn allocNominalType 'arena (self: &mut Resolver 'arena, info: NominalType) -> *unsafe mut NominalType {
1177
    // Nb. We don't attempt to de-duplicate nominal type entries,
1178
    // since they don't carry node information and we create
1179
    // placeholder entries when binding symbols.
1180
    let entry = try! alloc::allocRaw(
1181
        self.arena, @sizeOf(NominalType), @alignOf(NominalType)
1182
    ) as *unsafe mut NominalType;
1183
1184
    set *entry = info;
1185
1186
    return entry;
1187
}
1188
1189
/// Allocate the single runtime layout for a nominal declaration.
1190
unsafe fn allocLayout 'arena (self: &mut Resolver 'arena, value: Layout) -> *Layout {
1191
    let layout = try! alloc::alloc(&mut *self.arena, @sizeOf(Layout), @alignOf(Layout)) as *mut Layout;
1192
    set *layout = value;
1193
    return layout;
1194
}
1195
1196
/// Get the exact arguments of an applied nominal descriptor.
1197
export unsafe fn nominalApplication(info: *unsafe NominalType) -> ?*unsafe NominalApplication {
1198
    match *info {
1199
        case NominalType::Application(applied) => return applied,
1200
        case NominalType::Record(body) => return body.application,
1201
        case NominalType::Union(body) => return body.application,
1202
        else => return nil,
1203
    }
1204
}
1205
1206
/// Get source region parameters without forcing a recursive type's layout.
1207
unsafe fn nominalParameters 'arena (self: &mut Resolver 'arena, info: *unsafe NominalType) -> ?*RegionScope
1208
    throws (ResolveError)
1209
{
1210
    match *info {
1211
        case NominalType::Placeholder(node) => return try declarationRegions(self, node),
1212
        case NominalType::Resolving(node) => return try declarationRegions(self, node),
1213
        case NominalType::Application(applied) => return applied.parameters,
1214
        case NominalType::Record(body) => return body.regions,
1215
        case NominalType::Union(body) => return body.regions,
1216
    }
1217
}
1218
1219
/// Bind the regions declared by a nominal source node.
1220
unsafe fn declarationRegions 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> ?*RegionScope
1221
    throws (ResolveError)
1222
{
1223
    match node.value {
1224
        case ast::NodeValue::RecordDecl(decl) => return try bindRegions(self, node, decl.regions),
1225
        case ast::NodeValue::UnionDecl(decl) => return try bindRegions(self, node, decl.regions),
1226
        else => panic "declarationRegions: expected nominal declaration",
1227
    }
1228
}
1229
1230
/// Use a hinted application only for the same unapplied nominal declaration.
1231
unsafe fn hintedNominal(info: *unsafe NominalType, hint: Type) -> *unsafe NominalType {
1232
    if nominalApplication(info) <> nil {
1233
        return info;
1234
    }
1235
    let mut target = hint;
1236
    if let case Type::Optional(inner) = target {
1237
        set target = *inner;
1238
    }
1239
    if let case Type::Nominal(other) = target {
1240
        if let applied = nominalApplication(other); applied.base == info {
1241
            return other;
1242
        }
1243
    }
1244
    return info;
1245
}
1246
1247
/// Require explicit arguments for a parameterized nominal type.
1248
unsafe fn requireNominalArguments 'arena (self: &mut Resolver 'arena, info: *unsafe NominalType, site: *ast::Node)
1249
    throws (ResolveError)
1250
{
1251
    if nominalApplication(info) <> nil {
1252
        return;
1253
    }
1254
    if let parameters = try nominalParameters(self, info) {
1255
        throw emitError(self, site, ErrorKind::RegionArgumentCount(CountMismatch {
1256
            expected: parameters.entries.len, actual: 0,
1257
        }));
1258
    }
1259
}
1260
1261
/// Intern an exact nominal application before resolving its recursive members.
1262
unsafe fn internNominalApplication 'arena (
1263
    self: &mut Resolver 'arena, base: *unsafe NominalType, map: &RegionSubstitution
1264
) -> *unsafe mut NominalType {
1265
    let mut cursor = self.applications;
1266
    while let applied = cursor {
1267
        if applied.base == base {
1268
            let mut same = true;
1269
            for argument, i in applied.arguments {
1270
                let other = map.arguments[i] else panic "internNominalApplication: missing argument";
1271
                if argument.id <> other.id {
1272
                    set same = false;
1273
                    break;
1274
                }
1275
            }
1276
            if same {
1277
                return applied.view;
1278
            }
1279
        }
1280
        set cursor = applied.next;
1281
    }
1282
    let arguments = try! alloc::allocRawSlice(
1283
        self.arena, @sizeOf(*unsafe types::Region), @alignOf(*unsafe types::Region), map.arguments.len
1284
    ) as *unsafe mut [*unsafe types::Region];
1285
    for argument, i in map.arguments {
1286
        let region = argument else panic "internNominalApplication: incomplete map";
1287
        set arguments[i] = region;
1288
    }
1289
    let entry = try! alloc::allocRaw(
1290
        self.arena, @sizeOf(NominalApplication), @alignOf(NominalApplication)
1291
    ) as *unsafe mut NominalApplication;
1292
    let view = allocNominalType(self, NominalType::Application(entry));
1293
    set *entry = NominalApplication { base, parameters: map.parameters, arguments, view, next: self.applications };
1294
    set self.applications = entry;
1295
    return view;
1296
}
1297
1298
/// Check explicit region arguments and intern the applied nominal type.
1299
unsafe fn applyNominalRegions 'arena (
1300
    self: &mut Resolver 'arena, base: *unsafe NominalType, regions: *[*ast::Node], site: *ast::Node
1301
) -> *unsafe mut NominalType throws (ResolveError) {
1302
    if nominalApplication(base) <> nil {
1303
        throw emitError(self, site, ErrorKind::RegionArgumentCount(CountMismatch { expected: 0, actual: regions.len }));
1304
    }
1305
    let parameters = try nominalParameters(self, base);
1306
    let mut count: u32 = 0;
1307
    if let scope = parameters {
1308
        set count = scope.entries.len;
1309
    }
1310
    if count <> regions.len {
1311
        throw emitError(self, site, ErrorKind::RegionArgumentCount(CountMismatch { expected: count, actual: regions.len }));
1312
    }
1313
    let scope = parameters else panic "applyNominalRegions: empty application";
1314
    let map = regionSubstitution(self, scope);
1315
    for region, i in regions {
1316
        set map.arguments[i] = try resolveRegion(self, region);
1317
    }
1318
    try validateRegionArguments(self, &map, site);
1319
    return internNominalApplication(self, base, &map);
1320
}
1321
1322
/// Complete nominal views stored inline within an applied type.
1323
/// Pointer, slice, and cell targets have independent storage layouts.
1324
unsafe fn resolveInlineTypeViews 'arena (self: &mut Resolver 'arena, ty: Type, site: *ast::Node)
1325
    throws (ResolveError)
1326
{
1327
    match ty {
1328
        case Type::Nominal(info) => try ensureNominalResolved(self, info, site),
1329
        case Type::Array(array) => try resolveInlineTypeViews(self, *array.item, site),
1330
        case Type::Optional(inner) => try resolveInlineTypeViews(self, *inner, site),
1331
        else => {
1332
        },
1333
    }
1334
}
1335
1336
/// Resolve a substituted member view with the source declaration's shared layout.
1337
unsafe fn resolveNominalApplication 'arena (self: &mut Resolver 'arena, applied: *unsafe NominalApplication, site: *ast::Node)
1338
    throws (ResolveError)
1339
{
1340
    try ensureNominalResolved(self, applied.base, site);
1341
    let map = regionSubstitution(self, applied.parameters);
1342
    for argument, i in applied.arguments {
1343
        set map.arguments[i] = argument;
1344
    }
1345
    let allocator = alloc::arenaAllocator(self.arena);
1346
    match *applied.base {
1347
        case NominalType::Record(body) => {
1348
            let mut fields: *unsafe mut [RecordField] = &mut [];
1349
            for field in body.fields {
1350
                let fieldType = substituteRegions(self, &map, field.fieldType);
1351
                try resolveInlineTypeViews(self, fieldType, site);
1352
                fields.append(RecordField {
1353
                    name: field.name,
1354
                    fieldType,
1355
                    offset: field.offset,
1356
                }, allocator);
1357
            }
1358
            set *applied.view = NominalType::Record(RecordType {
1359
                regions: body.regions,
1360
                application: applied,
1361
                fields,
1362
                labeled: body.labeled,
1363
                layout: body.layout,
1364
                declaredLinear: body.declaredLinear,
1365
                declaredCopy: body.declaredCopy,
1366
            });
1367
        }
1368
        case NominalType::Union(body) => {
1369
            let mut variants: *unsafe mut [UnionVariant] = &mut [];
1370
            for variant in body.variants {
1371
                let valueType = substituteRegions(self, &map, variant.valueType);
1372
                try resolveInlineTypeViews(self, valueType, site);
1373
                variants.append(UnionVariant {
1374
                    name: variant.name,
1375
                    valueType,
1376
                    symbol: variant.symbol,
1377
                }, allocator);
1378
            }
1379
            set *applied.view = NominalType::Union(UnionType {
1380
                regions: body.regions,
1381
                application: applied,
1382
                variants,
1383
                layout: body.layout,
1384
                valOffset: body.valOffset,
1385
                isAllVoid: body.isAllVoid,
1386
                declaredLinear: body.declaredLinear,
1387
                declaredCopy: body.declaredCopy,
1388
            });
1389
        }
1390
        else => panic "resolveNominalApplication: unresolved base",
1391
    }
1392
}
1393
1394
/// Complete all applied member views before semantic metadata reaches lowering.
1395
unsafe fn resolveNominalApplications 'arena (self: &mut Resolver 'arena, site: *ast::Node) throws (ResolveError) {
1396
    let mut end: ?*unsafe NominalApplication = nil;
1397
    loop {
1398
        let first = self.applications;
1399
        let mut cursor = first;
1400
        while cursor <> end {
1401
            let applied = cursor else panic "resolveNominalApplications: invalid frontier";
1402
            try ensureNominalResolved(self, applied.view, site);
1403
            set cursor = applied.next;
1404
        }
1405
        if self.applications == first {
1406
            return;
1407
        }
1408
        set end = first;
1409
    }
1410
}
1411
1412
/// Allocate a function type descriptor and return a pointer to it.
1413
unsafe fn allocFnType 'arena (self: &mut Resolver 'arena, info: FnType) -> *FnType {
1414
    let entry = try! alloc::alloc(
1415
        &mut *self.arena, @sizeOf(FnType), @alignOf(FnType)
1416
    ) as *mut FnType;
1417
1418
    set *entry = info;
1419
1420
    return entry;
1421
}
1422
1423
/// Returns an error, if any, associated with the given node.
1424
fn errorForNode 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?Error {
1425
    for i in 0..self.errors.len {
1426
        let err = self.errors.entries[i];
1427
        if err.node == node {
1428
            return err;
1429
        }
1430
    }
1431
    return nil;
1432
}
1433
1434
/// Storage buffers used by the analyzer.
1435
export record ResolverStorage {
1436
    /// Node semantic metadata indexed by node ID.
1437
    nodeData: *mut [NodeData],
1438
    /// Package scope.
1439
    pkgScope: *unsafe mut Scope,
1440
    /// Error storage.
1441
    errors: *mut [Error],
1442
}
1443
1444
/// Input for resolving a single package.
1445
export record Pkg: Copy {
1446
    /// Root module entry.
1447
    rootEntry: *module::ModuleEntry,
1448
    /// Root AST node.
1449
    rootAst: *ast::Node,
1450
}
1451
1452
/// Construct a resolver with module context and backing storage.
1453
/// The arena owner and backing bytes must retain stable addresses during use.
1454
/// Arena reclamation can occur only after all metadata uses end.
1455
export unsafe fn resolver 'arena (
1456
    arena: &'arena mut alloc::Arena,
1457
    storage: ResolverStorage,
1458
    config: Config
1459
) -> Resolver 'arena {
1460
    let case ResolverStorage { nodeData, pkgScope, errors } = storage else panic "expected resolver storage";
1461
    let symbols = try! alloc::allocRawSlice(
1462
        arena, @sizeOf(*unsafe mut Symbol), @alignOf(*unsafe mut Symbol), MAX_MODULE_SYMBOLS
1463
    ) as *unsafe mut [*unsafe mut Symbol];
1464
1465
    // Initialize the root scope.
1466
    // TODO: Set this up when declaring `PKG_SCOPE`, not here.
1467
    set *pkgScope = Scope {
1468
        owner: nil,
1469
        parent: nil,
1470
        moduleId: nil,
1471
        symbols,
1472
        symbolsLen: 0,
1473
    };
1474
1475
    // Clear all node semantic metadata to sentinel values.
1476
    // TODO: Use array repeat literal?
1477
    for i in 0..nodeData.len {
1478
        set nodeData[i] = NodeData {
1479
            localCount: 0,
1480
            ty: Type::Unknown,
1481
            coercion: Coercion::Identity,
1482
            sym: nil,
1483
            constValue: nil,
1484
            scope: nil,
1485
            extra: NodeExtra::None,
1486
        };
1487
    }
1488
1489
    let mut moduleScopes: [?*unsafe mut Scope; module::MAX_MODULES] = undefined;
1490
    // TODO: Simplify.
1491
    for i in 0..moduleScopes.len {
1492
        set moduleScopes[i] = nil;
1493
    }
1494
    return Resolver 'arena {
1495
        regionScope: nil,
1496
        applications: nil,
1497
        scope: pkgScope,
1498
        pkgScope: pkgScope,
1499
        loopStack: undefined,
1500
        loopDepth: 0,
1501
        currentFn: nil,
1502
        currentFnNode: nil,
1503
        currentMod: 0,
1504
        inUnsafeContext: false,
1505
        config,
1506
        arena,
1507
        nodeData: NodeDataTable { entries: nodeData },
1508
        types: nil,
1509
        errors: DiagnosticBuffer { entries: errors, len: 0 },
1510
        // TODO: Shouldn't be undefined.
1511
        moduleGraph: undefined,
1512
        moduleScopes,
1513
        instances: undefined,
1514
        instancesLen: 0,
1515
        methods: undefined,
1516
        methodsLen: 0,
1517
    };
1518
}
1519
1520
/// Capture the current errors in an immutable arena allocation.
1521
/// The allocation must remain valid while the diagnostics are used.
1522
export unsafe fn diagnostics 'arena (self: &mut Resolver 'arena) -> Diagnostics {
1523
    let count = self.errors.len;
1524
    let entries = try! alloc::allocSlice(
1525
        self.arena, @sizeOf(Error), @alignOf(Error), count
1526
    ) as *mut [Error];
1527
    for i in 0..self.errors.len {
1528
        set entries[i] = self.errors.entries[i];
1529
    }
1530
    return Diagnostics { errors: entries };
1531
}
1532
1533
/// Return `true` if there are no errors in the diagnostics.
1534
export fn success(diag: &Diagnostics) -> bool {
1535
    return diag.errors.len == 0;
1536
}
1537
1538
/// Retrieve an error diagnostic by index, if present.
1539
export fn errorAt(errs: &[Error], index: u32) -> ?Error {
1540
    if index >= errs.len {
1541
        return nil;
1542
    }
1543
    return errs[index];
1544
}
1545
1546
/// Record an error diagnostic and return an error sentinel suitable for throwing.
1547
fn emitError 'arena (self: &mut Resolver 'arena, node: ?*ast::Node, kind: ErrorKind) -> ResolveError {
1548
    // If our error list is full, just return an error without recording it.
1549
    if self.errors.len >= self.errors.entries.len {
1550
        return ResolveError::Failure;
1551
    }
1552
    // Don't record more than one error per node.
1553
    if let n = node; errorForNode(self, n) <> nil {
1554
        return ResolveError::Failure;
1555
    }
1556
    let idx = self.errors.len;
1557
    set self.errors.entries[idx] = Error { kind, node, moduleId: self.currentMod };
1558
    set self.errors.len = idx + 1;
1559
1560
    return ResolveError::Failure;
1561
}
1562
1563
/// Like [`emitError`], but for type mismatches specifically.
1564
unsafe fn emitTypeMismatch 'arena (self: &mut Resolver 'arena, node: ?*ast::Node, mismatch: TypeMismatch) -> ResolveError {
1565
    return emitError(self, node, ErrorKind::TypeMismatch(mismatch));
1566
}
1567
1568
/// Allocate a scope object with the given symbol capacity.
1569
unsafe fn allocScope 'arena (self: &mut Resolver 'arena, owner: *ast::Node, capacity: u32) -> *unsafe mut Scope {
1570
    // Check for an existing scope for this node, and don't allocate a new
1571
    // one in that case.
1572
    if let scope = scopeFor(self, owner) {
1573
        return scope;
1574
    }
1575
    assert owner.id < self.nodeData.entries.len, "allocScope: node ID out of bounds";
1576
    let p = try! alloc::allocRaw(self.arena, @sizeOf(Scope), @alignOf(Scope));
1577
    let entry = p as *unsafe mut Scope;
1578
1579
    // Allocate symbols from the arena.
1580
    let symbols = try! alloc::allocRawSlice(
1581
        self.arena, @sizeOf(*unsafe mut Symbol), @alignOf(*unsafe mut Symbol), capacity
1582
    ) as *unsafe mut [*unsafe mut Symbol];
1583
1584
    set *entry = Scope { owner, parent: nil, moduleId: nil, symbols, symbolsLen: 0 };
1585
    set self.nodeData.entries[owner.id].scope = entry;
1586
1587
    return entry;
1588
}
1589
1590
/// Enter a new local scope that is the child of the current scope.
1591
/// This creates a parent/child relationship that means that lookups in the
1592
/// child scope can recurse upwards.
1593
export unsafe fn enterScope 'arena (self: &mut Resolver 'arena, owner: *ast::Node) -> *unsafe Scope {
1594
    let scope = allocScope(self, owner, MAX_LOCAL_SYMBOLS);
1595
    set scope.parent = self.scope;
1596
    set self.scope = scope;
1597
    return scope;
1598
}
1599
1600
/// Enter a module scope. Returns an object that can be used to exit the scope.
1601
export unsafe fn enterModuleScope 'arena (self: &mut Resolver 'arena, owner: *ast::Node, module: *module::ModuleEntry) -> ModuleScope {
1602
    let prevScope = self.scope;
1603
    let prevMod = self.currentMod;
1604
    let scope = allocScope(self, owner, MAX_MODULE_SYMBOLS);
1605
1606
    set self.scope = scope;
1607
    set self.scope.moduleId = module.id;
1608
    set self.currentMod = module.id;
1609
    // TODO: Allow any unsigned integer to index an array.
1610
    set self.moduleScopes[module.id as u32] = scope;
1611
1612
    return ModuleScope { root: owner, entry: module, newScope: scope, prevScope, prevMod };
1613
}
1614
1615
/// Enter a sub-module. Changes the current scope into that of the sub-module.
1616
unsafe fn enterSubModule 'arena (self: &mut Resolver 'arena, name: *[u8], node: *ast::Node) -> ModuleScope throws (ResolveError) {
1617
    let modEntry = module::findChild(self.moduleGraph, name, self.currentMod)
1618
        else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
1619
    let modRoot = module::astFor(modEntry)
1620
        else panic "enterSubModule: analyzing module that wasn't parsed";
1621
1622
    return enterModuleScope(self, modRoot, modEntry);
1623
}
1624
1625
/// Exit a module scope, given the object returned by `enterModuleScope`.
1626
export fn exitModuleScope 'arena (self: &mut Resolver 'arena, entry: ModuleScope) {
1627
    set self.scope = entry.prevScope;
1628
    set self.currentMod = entry.prevMod;
1629
}
1630
1631
/// Exit the most recent scope.
1632
export unsafe fn exitScope 'arena (self: &mut Resolver 'arena) {
1633
    let parent = self.scope.parent else {
1634
        // TODO: This should be a panic, but one of the tests hits this
1635
        // clause, which might be a bug in the generator.
1636
        return;
1637
    };
1638
    set self.scope = parent;
1639
}
1640
1641
/// Visit the body of a loop while tracking nesting depth.
1642
unsafe fn visitLoop 'arena (self: &mut Resolver 'arena, body: *ast::Node) -> Type
1643
    throws (ResolveError)
1644
{
1645
    assert self.loopDepth < MAX_LOOP_DEPTH, "visitLoop: loop nesting depth exceeded";
1646
    set self.loopStack[self.loopDepth] = LoopCtx { hasBreak: false };
1647
    set self.loopDepth += 1;
1648
1649
    let ty = try infer(self, body) catch {
1650
        assert self.loopDepth <> 0, "visitLoop: loop depth underflow";
1651
        set self.loopDepth -= 1;
1652
        throw ResolveError::Failure;
1653
    };
1654
    // Pop and check if break was encountered.
1655
    set self.loopDepth -= 1;
1656
1657
    if self.loopStack[self.loopDepth].hasBreak {
1658
        return Type::Void;
1659
    }
1660
    return Type::Never;
1661
}
1662
1663
/// Require that loop control statements appear inside a loop.
1664
unsafe fn ensureInsideLoop 'arena (self: &mut Resolver 'arena, node: *ast::Node) throws (ResolveError) {
1665
    if self.loopDepth == 0 {
1666
        throw emitError(self, node, ErrorKind::InvalidLoopControl);
1667
    }
1668
}
1669
1670
/// Bind a loop pattern to the provided type.
1671
unsafe fn bindForLoopPattern 'arena (self: &mut Resolver 'arena, pattern: *ast::Node, ty: Type, mutable: bool)
1672
    throws (ResolveError)
1673
{
1674
    match pattern.value {
1675
        case ast::NodeValue::Placeholder, ast::NodeValue::Ident(_) => {
1676
            let _ = try bindValueIdent(self, pattern, pattern, ty, mutable, 0, 0);
1677
        }
1678
        else => {
1679
            let actualTy = try checkAssignable(self, pattern, ty);
1680
            setNodeType(self, pattern, actualTy);
1681
        }
1682
    }
1683
}
1684
1685
/// Set the expected return type for a new function body.
1686
unsafe fn enterFn 'arena (self: &mut Resolver 'arena, node: *ast::Node, ty: &FnType) {
1687
    assert self.currentFn == nil, "enterFn: already in a function";
1688
    set self.currentFn = *ty;
1689
    set self.currentFnNode = node;
1690
    enterScope(self, node);
1691
}
1692
1693
/// Clear the expected return type when leaving a function body.
1694
unsafe fn exitFn 'arena (self: &mut Resolver 'arena) {
1695
    if self.currentFn == nil {
1696
        // TODO: This should be a panic, but one of the tests hits this
1697
        // clause, which might be a bug in the generator.
1698
        return;
1699
    }
1700
    set self.currentFn = nil;
1701
    set self.currentFnNode = nil;
1702
    exitScope(self);
1703
}
1704
1705
/// Extract the identifier text from a node.
1706
unsafe fn nodeName 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> *[u8]
1707
    throws (ResolveError)
1708
{
1709
    let case ast::NodeValue::Ident(name) = node.value
1710
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
1711
    return name;
1712
}
1713
1714
/// Associate a resolved symbol with an AST node.
1715
fn setNodeSymbol 'arena (self: &mut Resolver 'arena, node: *ast::Node, symbol: *unsafe mut Symbol) {
1716
    if let existingSym = self.nodeData.entries[node.id].sym {
1717
        panic "setNodeSymbol: a symbol is already associated with this node";
1718
    }
1719
    set self.nodeData.entries[node.id].sym = symbol;
1720
}
1721
1722
/// Associate a resolved type with an AST node and return it.
1723
fn setNodeType 'arena (self: &mut Resolver 'arena, node: *ast::Node, ty: Type) -> Type {
1724
    if ty == Type::Unknown {
1725
        // In this case, we simply don't associate a type.
1726
        return ty;
1727
    }
1728
    set self.nodeData.entries[node.id].ty = ty;
1729
1730
    return ty;
1731
}
1732
1733
/// Unify the types of two branches for control flow. Returns `never` only if
1734
/// both branches diverge, otherwise returns `void`. If the else branch is
1735
/// absent, we assume it doesn't diverge.
1736
fn unifyBranches(left: Type, right: ?Type) -> Type {
1737
    if left == Type::Never {
1738
        if let ty = right; ty == Type::Never {
1739
            return Type::Never;
1740
        }
1741
    }
1742
    return Type::Void;
1743
}
1744
1745
/// Associate a coercion plan with an AST node.
1746
fn setNodeCoercion 'arena (self: &mut Resolver 'arena, node: *ast::Node, coercion: Coercion) -> Coercion {
1747
    if coercion == Coercion::Identity {
1748
        return coercion;
1749
    }
1750
    set self.nodeData.entries[node.id].coercion = coercion;
1751
1752
    return coercion;
1753
}
1754
1755
/// Associate a constant value with an AST node.
1756
fn setNodeConstValue 'arena (self: &mut Resolver 'arena, node: *ast::Node, value: ConstValue) {
1757
    set self.nodeData.entries[node.id].constValue = value;
1758
}
1759
1760
/// Associate a record field index with a record literal field node.
1761
fn setRecordFieldIndex 'arena (self: &mut Resolver 'arena, node: *ast::Node, index: u32) {
1762
    set self.nodeData.entries[node.id].extra = NodeExtra::RecordField { index };
1763
}
1764
1765
/// Associate slice range metadata with a subscript expression.
1766
fn setSliceRangeInfo 'arena (self: &mut Resolver 'arena, node: *ast::Node, info: SliceRangeInfo) {
1767
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info);
1768
}
1769
1770
/// Associate union variant metadata with a pattern or constructor node.
1771
fn setVariantInfo 'arena (self: &mut Resolver 'arena, node: *ast::Node, ordinal: u32, tag: u32) {
1772
    set self.nodeData.entries[node.id].extra = NodeExtra::UnionVariant { ordinal, tag };
1773
}
1774
1775
/// Associate trait method call metadata with a call node.
1776
fn setTraitMethodCall 'arena (self: &mut Resolver 'arena, node: *ast::Node, traitInfo: *unsafe TraitType, methodIndex: u32) {
1777
    set self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex };
1778
}
1779
1780
/// Associate for-loop metadata with a for-loop node.
1781
fn setForLoopInfo 'arena (self: &mut Resolver 'arena, node: *ast::Node, info: ForLoopInfo) {
1782
    set self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info);
1783
}
1784
1785
/// Retrieve the constant value associated with a node, if any.
1786
export fn constValueEntry 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?ConstValue {
1787
    return self.nodeData.entries[node.id].constValue;
1788
}
1789
1790
/// Get the resolved record field index for a record literal field node.
1791
export fn recordFieldIndexFor 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?u32 {
1792
    if let case NodeExtra::RecordField { index } = self.nodeData.entries[node.id].extra {
1793
        return index;
1794
    }
1795
    return nil;
1796
}
1797
1798
/// Get the slice range metadata for a subscript expression with a range index.
1799
export fn sliceRangeInfoFor 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?SliceRangeInfo {
1800
    if let case NodeExtra::SliceRange(info) = self.nodeData.entries[node.id].extra {
1801
        return info;
1802
    }
1803
    return nil;
1804
}
1805
1806
/// Get the for-loop metadata for a for-loop node.
1807
export fn forLoopInfoFor 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?ForLoopInfo {
1808
    if let case NodeExtra::ForLoop(info) = self.nodeData.entries[node.id].extra {
1809
        return info;
1810
    }
1811
    return nil;
1812
}
1813
1814
/// Associate match prong metadata with a match prong node.
1815
fn setProngCatchAll 'arena (self: &mut Resolver 'arena, node: *ast::Node, catchAll: bool) {
1816
    set self.nodeData.entries[node.id].extra = NodeExtra::MatchProng { catchAll };
1817
}
1818
1819
/// Check if a prong is catch-all.
1820
export fn isProngCatchAll 'arena (self: &Resolver 'arena, node: *ast::Node) -> bool {
1821
    if let case NodeExtra::MatchProng { catchAll } = self.nodeData.entries[node.id].extra {
1822
        return catchAll;
1823
    }
1824
    return false;
1825
}
1826
1827
/// Set match metadata.
1828
fn setMatchConst 'arena (self: &mut Resolver 'arena, node: *ast::Node, isConst: bool) {
1829
    set self.nodeData.entries[node.id].extra = NodeExtra::Match { isConst };
1830
}
1831
1832
/// Check if a match has all constant patterns.
1833
export fn isMatchConst 'arena (self: &Resolver 'arena, node: *ast::Node) -> bool {
1834
    if let case NodeExtra::Match { isConst } = self.nodeData.entries[node.id].extra {
1835
        return isConst;
1836
    }
1837
    return false;
1838
}
1839
1840
/// Get the resolver metadata for a node.
1841
export fn nodeData 'arena (self: &Resolver 'arena, node: *ast::Node) -> NodeData {
1842
    return self.nodeData.entries[node.id];
1843
}
1844
1845
/// Get the type for a node, or `nil` if unknown.
1846
export fn typeFor 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?Type {
1847
    let ty = self.nodeData.entries[node.id].ty;
1848
    if ty == Type::Unknown {
1849
        return nil;
1850
    }
1851
    return ty;
1852
}
1853
1854
/// Get the scope associated with a node.
1855
export fn scopeFor 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?*unsafe mut Scope {
1856
    return self.nodeData.entries[node.id].scope;
1857
}
1858
1859
/// Get the symbol bound to a node.
1860
export fn symbolFor 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?*unsafe mut Symbol {
1861
    return self.nodeData.entries[node.id].sym;
1862
}
1863
1864
/// Get the coercion plan associated with a node, if any.
1865
export fn coercionFor 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?Coercion {
1866
    let c = self.nodeData.entries[node.id].coercion;
1867
    if c == Coercion::Identity {
1868
        return nil;
1869
    }
1870
    return c;
1871
}
1872
1873
/// Get the module ID for a symbol by walking up its scope chain.
1874
export unsafe fn moduleIdForSymbol 'arena (self: &Resolver 'arena, sym: *unsafe Symbol) -> ?u16 {
1875
    // For module-level symbols, return the cached module ID.
1876
    if let id = sym.moduleId {
1877
        return id;
1878
    }
1879
    // For module symbols, return the module ID directly.
1880
    if let case SymbolData::Module { entry, .. } = sym.data {
1881
        return entry.id;
1882
    }
1883
    // If this node has its own scope (functions, types, etc.), walk up from there.
1884
    if let scope = self.nodeData.entries[sym.node.id].scope {
1885
        return findModuleForScope(scope);
1886
    }
1887
    return nil;
1888
}
1889
1890
/// Get the binding node for a variant pattern.
1891
/// Returns the argument node if this is a variant constructor with a non-placeholder binding.
1892
export unsafe fn variantPatternBinding 'arena (self: &Resolver 'arena, pattern: *ast::Node) -> ?*ast::Node {
1893
    let case ast::NodeValue::Call(call) = pattern.value
1894
        else return nil;
1895
    let sym = symbolFor(self, call.callee)
1896
        else return nil;
1897
    let case SymbolData::Variant { .. } = sym.data
1898
        else return nil;
1899
1900
    if call.args.len == 0 {
1901
        return nil;
1902
    }
1903
    let arg = call.args[0];
1904
1905
    if let case ast::NodeValue::Placeholder = arg.value {
1906
        return nil;
1907
    }
1908
    return arg;
1909
}
1910
1911
/// Allocate a new symbol, and return a reference to it.
1912
unsafe fn allocSymbol 'arena (self: &mut Resolver 'arena, data: SymbolData, name: *[u8], node: *ast::Node, attrs: u32) -> *unsafe mut Symbol {
1913
    let sym = try! alloc::allocRaw(self.arena, @sizeOf(Symbol), @alignOf(Symbol)) as *unsafe mut Symbol;
1914
    set *sym = Symbol { name, data, attrs, node, moduleId: nil };
1915
1916
    return sym;
1917
}
1918
1919
/// Check that a type is boolean, otherwise throw an error.
1920
unsafe fn checkBoolean 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> Type throws (ResolveError) {
1921
    return try checkEqual(self, node, Type::Bool);
1922
}
1923
1924
/// Check that a type is numeric, otherwise throw an error.
1925
unsafe fn checkNumeric 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> Type throws (ResolveError) {
1926
    let ty = try infer(self, node);
1927
    if not isNumericType(ty) {
1928
        throw emitError(self, node, ErrorKind::ExpectedNumeric);
1929
    }
1930
    return ty;
1931
}
1932
1933
/// Check if a type is a numeric type.
1934
fn isNumericType(ty: Type) -> bool {
1935
    match ty {
1936
        case Type::U8, Type::U16, Type::U32, Type::U64,
1937
             Type::I8, Type::I16, Type::I32, Type::I64,
1938
             Type::Int => return true,
1939
        else => return false,
1940
    }
1941
}
1942
1943
/// Check if a type is an unsigned integer type.
1944
export fn isUnsignedIntegerType(ty: Type) -> bool {
1945
    match ty {
1946
        case Type::U8, Type::U16, Type::U32, Type::U64 => return true,
1947
        else => return false,
1948
    }
1949
}
1950
1951
/// Return the maximum of two u32 values.
1952
fn max(a: u32, b: u32) -> u32 {
1953
    if a > b {
1954
        return a;
1955
    }
1956
    return b;
1957
}
1958
1959
/// Get the layout of a type.
1960
export unsafe fn getTypeLayout(ty: Type) -> Layout {
1961
    match ty {
1962
        case Type::Pointer { .. } => return Layout {
1963
            size: PTR_SIZE, alignment: PTR_SIZE
1964
        },
1965
        case Type::Slice { .. }, Type::TraitObject { .. }, Type::Session(_) =>
1966
            return Layout { size: PTR_SIZE * 2, alignment: PTR_SIZE },
1967
        case Type::Void, Type::Never => return Layout { size: 0, alignment: 0 },
1968
        case Type::Bool, Type::U8, Type::I8 => return Layout { size: 1, alignment: 1 },
1969
        case Type::U16, Type::I16 => return Layout { size: 2, alignment: 2 },
1970
        case Type::U32, Type::I32 => return Layout { size: 4, alignment: 4 },
1971
        case Type::Int => return Layout { size: 8, alignment: 8 },
1972
        case Type::U64, Type::I64 => return Layout { size: 8, alignment: 8 },
1973
        case Type::Fn(_) => return Layout { size: PTR_SIZE, alignment: PTR_SIZE },
1974
        case Type::Cell { .. } => return Layout {
1975
            size: PTR_SIZE, alignment: PTR_SIZE
1976
        },
1977
        case Type::Array(arr) => return getArrayLayout(arr),
1978
        case Type::Optional(inner) => return getOptionalLayout(*inner),
1979
        case Type::Nominal(info) => return getNominalLayout(*info),
1980
        else => {
1981
            panic "getTypeLayout: the given type cannot be layed out";
1982
        }
1983
    }
1984
}
1985
1986
/// Get the layout of a type or value.
1987
export unsafe fn getLayout 'arena (self: &Resolver 'arena, node: *ast::Node, ty: Type) -> Layout {
1988
    let mut layout = getTypeLayout(ty);
1989
    // Check for symbol-specific alignment override.
1990
    if let sym = symbolFor(self, node) {
1991
        if let case SymbolData::Value { alignment, .. } = sym.data {
1992
            if alignment > 0 {
1993
                set layout.alignment = alignment;
1994
            }
1995
        }
1996
    }
1997
    return layout;
1998
}
1999
2000
/// Get the layout of an array type.
2001
export unsafe fn getArrayLayout(arr: ArrayType) -> Layout {
2002
    let itemLayout = getTypeLayout(*arr.item);
2003
    return Layout {
2004
        size: itemLayout.size * arr.length,
2005
        alignment: itemLayout.alignment,
2006
    };
2007
}
2008
2009
/// Get the layout of an optional type.
2010
export unsafe fn getOptionalLayout(inner: Type) -> Layout {
2011
    // Nullable types use null pointer optimization -- no tag byte needed.
2012
    if isNullableType(inner) {
2013
        return getTypeLayout(inner);
2014
    }
2015
    let innerLayout = getTypeLayout(inner);
2016
    let tagSize: u32 = 1;
2017
    let valOffset = mem::alignUp(tagSize, innerLayout.alignment);
2018
    let alignment = max(innerLayout.alignment, 1);
2019
2020
    return Layout {
2021
        size: mem::alignUp(valOffset + innerLayout.size, alignment),
2022
        alignment,
2023
    };
2024
}
2025
2026
/// Get the payload offset within an optional aggregate.
2027
export unsafe fn getOptionalValOffset(inner: Type) -> u32 {
2028
    let innerLayout = getTypeLayout(inner);
2029
    return mem::alignUp(1, innerLayout.alignment);
2030
}
2031
2032
/// Check if a type is optional.
2033
export fn isOptionalType(ty: Type) -> bool {
2034
    match ty {
2035
        case Type::Optional(_) => return true,
2036
        else => return false,
2037
    }
2038
}
2039
2040
/// Check if a type uses null pointer optimization.
2041
/// This applies to optional pointers `?*T` and optional slices `?*[T]`,
2042
/// where `nil` is represented as a null data pointer with no tag byte.
2043
export fn isOptionalPointer(ty: Type) -> bool {
2044
    if let case Type::Optional(inner) = ty {
2045
        return isNullableType(*inner);
2046
    }
2047
    return false;
2048
}
2049
2050
/// Check if a type uses the optional aggregate representation.
2051
export fn isOptionalAggregate(ty: Type) -> bool {
2052
    if let case Type::Optional(inner) = ty {
2053
        return not isNullableType(*inner);
2054
    }
2055
    return false;
2056
}
2057
2058
/// Check if a type can use null to represent `nil`.
2059
/// Pointers and slices have a data pointer that is never null when valid.
2060
export fn isNullableType(ty: Type) -> bool {
2061
    match ty {
2062
        case Type::Pointer { .. }, Type::Slice { .. } => return true,
2063
        else => return false,
2064
    }
2065
}
2066
2067
/// Get the layout of a nominal type.
2068
export fn getNominalLayout(info: NominalType) -> Layout {
2069
    match info {
2070
        case NominalType::Placeholder(_), NominalType::Resolving(_), NominalType::Application(_) => {
2071
            panic "getNominalLayout: unresolved type";
2072
        }
2073
        case NominalType::Record(recordType) => {
2074
            return *recordType.layout;
2075
        }
2076
        case NominalType::Union(unionType) => {
2077
            return *unionType.layout;
2078
        }
2079
    }
2080
}
2081
2082
/// Get the layout of a result aggregate with a tag and the larger payload.
2083
export unsafe fn getResultLayout(payload: Type, throwList: *[*Type]) -> Layout {
2084
    let payloadLayout = getTypeLayout(payload);
2085
    let mut maxSize = payloadLayout.size;
2086
    let mut maxAlign = payloadLayout.alignment;
2087
2088
    for errType in throwList {
2089
        let errLayout = getTypeLayout(*errType);
2090
        set maxSize = max(maxSize, errLayout.size);
2091
        set maxAlign = max(maxAlign, errLayout.alignment);
2092
    }
2093
    return Layout {
2094
        size: PTR_SIZE + maxSize,
2095
        alignment: max(PTR_SIZE, maxAlign),
2096
    };
2097
}
2098
2099
/// Compute the layout for a union given its resolved variants.
2100
unsafe fn computeUnionLayout(variants: *unsafe [UnionVariant]) -> UnionLayoutInfo {
2101
    let tagSize: u32 = 1;
2102
    let mut maxVarSize: u32 = 0;
2103
    let mut maxVarAlign: u32 = 1;
2104
    let mut isAllVoid: bool = true;
2105
2106
    for variant in variants {
2107
        if variant.valueType <> Type::Void {
2108
            set isAllVoid = false;
2109
            let payloadLayout = getTypeLayout(variant.valueType);
2110
            set maxVarSize = max(maxVarSize, payloadLayout.size);
2111
            set maxVarAlign = max(maxVarAlign, payloadLayout.alignment);
2112
        }
2113
    }
2114
    let unionAlignment: u32 = max(1, maxVarAlign);
2115
    let unionValOffset: u32 = mem::alignUp(tagSize, maxVarAlign);
2116
    let unionLayout = Layout {
2117
        size: mem::alignUp(unionValOffset + maxVarSize, unionAlignment),
2118
        alignment: unionAlignment,
2119
    };
2120
    return UnionLayoutInfo { layout: unionLayout, valOffset: unionValOffset, isAllVoid };
2121
}
2122
2123
/// Compute the discriminant tag for a variant, advancing the iota counter.
2124
/// If the variant has an explicit `= N` value, uses that; otherwise uses iota.
2125
fn variantTag(variantDecl: ast::UnionDeclVariant, iota: &mut u32) -> u32 {
2126
    let mut tag: u32 = *iota;
2127
    if let valueNode = variantDecl.value {
2128
        let case ast::NodeValue::Number(lit) = valueNode.value
2129
            else panic "variantTag: expected number literal";
2130
        set tag = lit.magnitude as u32;
2131
    }
2132
    set *iota = tag + 1;
2133
    return tag;
2134
}
2135
2136
/// Check if a type is a union without payloads.
2137
export unsafe fn isVoidUnion(ty: Type) -> bool {
2138
    let case Type::Nominal(NominalType::Union(unionType)) = ty
2139
        else return false;
2140
    return unionType.isAllVoid;
2141
}
2142
2143
/// Check if a type should be treated as an address-like value.
2144
fn isAddressType(ty: Type) -> bool {
2145
    if isNullableType(ty) {
2146
        return true;
2147
    }
2148
    match ty {
2149
        case Type::Fn(_) => return true,
2150
        else => return false,
2151
    }
2152
}
2153
2154
/// Return the representable range for an integer type.
2155
fn integerRange(ty: Type) -> ?IntegerRange {
2156
    match ty {
2157
        case Type::I8 => return IntegerRange::Signed {
2158
            bits: 8,
2159
            min: I8_MIN as i64,
2160
            max: I8_MAX as i64,
2161
            lim: (I8_MAX as u64) + 1,
2162
        },
2163
        case Type::I16 => return IntegerRange::Signed {
2164
            bits: 16,
2165
            min: I16_MIN as i64,
2166
            max: I16_MAX as i64,
2167
            lim: (I16_MAX as u64) + 1,
2168
        },
2169
        case Type::I32 => return IntegerRange::Signed {
2170
            bits: 32,
2171
            min: I32_MIN as i64,
2172
            max: I32_MAX as i64,
2173
            lim: (I32_MAX as u64) + 1,
2174
        },
2175
        case Type::I64, Type::Int => return IntegerRange::Signed {
2176
            bits: 64,
2177
            min: I64_MIN,
2178
            max: I64_MAX,
2179
            lim: (I64_MAX as u64) + 1,
2180
        },
2181
        case Type::U8 => return IntegerRange::Unsigned { bits: 8, max: U8_MAX as u64 },
2182
        case Type::U16 => return IntegerRange::Unsigned { bits: 16, max: U16_MAX as u64 },
2183
        case Type::U32 => return IntegerRange::Unsigned { bits: 32, max: parser::U32_MAX as u64 },
2184
        case Type::U64 => return IntegerRange::Unsigned { bits: 64, max: parser::U64_MAX },
2185
        else => return nil,
2186
    }
2187
}
2188
2189
/// Validate that an integer constant fits within the target type's range.
2190
fn validateConstIntRange(value: ConstValue, target: Type) -> bool {
2191
    let range = integerRange(target)
2192
        else panic "validateConstIntRange: expected integer type";
2193
    let case ConstValue::Int(int) = value
2194
        else panic "validateConstIntRange: expected integer constant";
2195
2196
    match range {
2197
        case IntegerRange::Signed { lim, .. } => {
2198
            if int.negative {
2199
                if int.magnitude > lim {
2200
                    return false;
2201
                }
2202
                return true;
2203
            }
2204
            if int.magnitude > lim - 1 {
2205
                return false;
2206
            }
2207
            return true;
2208
        }
2209
        case IntegerRange::Unsigned { max, .. } => {
2210
            if int.negative or int.magnitude > max {
2211
                return false;
2212
            }
2213
            return true;
2214
        }
2215
    }
2216
}
2217
2218
/// Ensure all nested nominal types in a type are resolved.
2219
unsafe fn ensureTypeResolved 'arena (self: &mut Resolver 'arena, ty: Type, site: *ast::Node) throws (ResolveError) {
2220
    match ty {
2221
        case Type::Nominal(info) => try ensureNominalResolved(self, info, site),
2222
        // Pointer and slice layouts do not depend on their element layout.
2223
        case Type::Pointer { .. }, Type::Slice { .. } => {
2224
        },
2225
        case Type::Cell { payload, .. } => try validateCellPayload(self, site, *payload),
2226
        case Type::Array(arr) => try ensureTypeResolved(self, *arr.item, site),
2227
        case Type::Optional(inner) => try ensureTypeResolved(self, *inner, site),
2228
        else => {},
2229
    }
2230
}
2231
2232
/// Ensure a nominal type has its body resolved.
2233
unsafe fn ensureNominalResolved 'arena (self: &mut Resolver 'arena, tyInfo: *unsafe NominalType, site: *ast::Node)
2234
    throws (ResolveError)
2235
{
2236
    if let case NominalType::Application(applied) = *tyInfo {
2237
        try resolveNominalApplication(self, applied, site);
2238
        return;
2239
    }
2240
    if let case NominalType::Resolving(_) = *tyInfo {
2241
        throw emitError(self, site, ErrorKind::RecursiveType);
2242
    }
2243
    if let case NominalType::Placeholder(declNode) = *tyInfo {
2244
        // When resolving on-demand (e.g. from a child module), switch to the
2245
        // declaring module's scope so field type lookups find the right symbols.
2246
        let prevScope = self.scope;
2247
        let prevMod = self.currentMod;
2248
2249
        if let sym = symbolFor(self, declNode) {
2250
            if let mid = sym.moduleId {
2251
                if (mid as u32) < self.moduleScopes.len {
2252
                    if let ms = self.moduleScopes[mid as u32] {
2253
                        set self.scope = ms;
2254
                        set self.currentMod = mid;
2255
                    }
2256
                }
2257
            }
2258
        }
2259
2260
        match declNode.value {
2261
            case ast::NodeValue::RecordDecl(decl) => {
2262
                try resolveRecordBody(self, declNode, decl) catch error {
2263
                    set self.scope = prevScope;
2264
                    set self.currentMod = prevMod;
2265
                    throw error;
2266
                };
2267
            }
2268
            case ast::NodeValue::UnionDecl(decl) => {
2269
                try resolveUnionBody(self, declNode, decl) catch error {
2270
                    set self.scope = prevScope;
2271
                    set self.currentMod = prevMod;
2272
                    throw error;
2273
                };
2274
            }
2275
            else => {},
2276
        }
2277
        set self.scope = prevScope;
2278
        set self.currentMod = prevMod;
2279
    }
2280
}
2281
2282
/// Check if all elements in a node list are assignable to the target type.
2283
unsafe fn isListAssignable 'arena (self: &mut Resolver 'arena, targetType: Type, items: *[*ast::Node]) -> bool {
2284
    for itemNode in items {
2285
        let elemTy = typeFor(self, itemNode)
2286
            else return false;
2287
        if let _ = isAssignable(self, targetType, elemTy, itemNode) {
2288
            // Do nothing.
2289
        } else {
2290
            return false;
2291
        }
2292
    }
2293
    return true;
2294
}
2295
2296
/// Return whether pointer classes are compatible in the current safety context.
2297
fn pointerClassesAssignable(
2298
    to: types::PointerClass,
2299
    from: types::PointerClass,
2300
    inUnsafeContext: bool,
2301
) -> bool {
2302
    return to == from or (
2303
        to == types::PointerClass::Ref
2304
        and (types::isReference(from) or from == types::PointerClass::Owned
2305
            or (from == types::PointerClass::Unsafe and inUnsafeContext))
2306
    );
2307
}
2308
2309
/// Limit an exclusive value's implicit borrow to its owner's borrow.
2310
unsafe fn assignableValueType 'arena (self: &mut Resolver 'arena, node: *ast::Node, source: Type) -> Type {
2311
    match source {
2312
        case Type::Pointer { class, target, mutable: true } => {
2313
            let usable = pointerAddressClass(self, node, class, true);
2314
            return Type::Pointer { class: usable, target, mutable: true };
2315
        }
2316
        case Type::Slice { class, item, mutable: true } => {
2317
            let usable = pointerAddressClass(self, node, class, true);
2318
            return Type::Slice { class: usable, item, mutable: true };
2319
        }
2320
        case Type::TraitObject { class, traitInfo, mutable: true } => {
2321
            let usable = pointerAddressClass(self, node, class, true);
2322
            return Type::TraitObject { class: usable, traitInfo, mutable: true };
2323
        }
2324
        case Type::Optional(inner) => {
2325
            let value = assignableValueType(self, node, *inner);
2326
            if typesEqual(value, *inner) {
2327
                return source;
2328
            }
2329
            return Type::Optional(allocType(self, value));
2330
        }
2331
        else => return source,
2332
    }
2333
}
2334
2335
/// Check if the `from` type is assignable to the `to` type, and return a
2336
/// coercion plan if so.
2337
/// Referenced storage requires equal element types. Function values may gain
2338
/// an unsafe call requirement.
2339
unsafe fn isAssignable 'arena (self: &mut Resolver 'arena, to: Type, source: Type, rval: *ast::Node) -> ?Coercion {
2340
    let from = assignableValueType(self, rval, source);
2341
    if to == Type::Unknown or from == Type::Unknown {
2342
        return nil;
2343
    }
2344
    if from == Type::Undefined {
2345
        if containsRegion(to) {
2346
            return nil;
2347
        }
2348
        if to == Type::Never {
2349
            return nil;
2350
        }
2351
        // TODO: Don't let `undefined` be used in place of functions and other
2352
        // non-data types.
2353
        return Coercion::Identity;
2354
    }
2355
    // The "never" type can always be assigned, since the code path is never
2356
    // executed.
2357
    if from == Type::Never {
2358
        return Coercion::Identity;
2359
    }
2360
    if to == from {
2361
        return Coercion::Identity;
2362
    }
2363
    if let case Type::Cell { class, payload } = to {
2364
        let case Type::Cell { class: sourceClass, payload: sourcePayload } = from else return nil;
2365
        if pointerClassesAssignable(class, sourceClass, self.inUnsafeContext) and typesEqual(*payload, *sourcePayload) {
2366
            return Coercion::Identity;
2367
        }
2368
        return nil;
2369
    }
2370
    if let case Type::Pointer { class: lhsClass, target: lhsTarget, mutable: lhsMutable } = to {
2371
        let case Type::Pointer { class: rhsClass, target: rhsTarget, mutable: rhsMutable } = from
2372
            else return nil;
2373
        if not pointerClassesAssignable(lhsClass, rhsClass, self.inUnsafeContext) {
2374
            return nil;
2375
        }
2376
        // Allow coercion from `*T` to `*opaque`, and mutable counterparts.
2377
        if *lhsTarget == Type::Opaque {
2378
            if lhsMutable and not rhsMutable {
2379
                return nil;
2380
            }
2381
            return Coercion::Identity;
2382
        }
2383
        if lhsMutable and not rhsMutable {
2384
            return nil;
2385
        }
2386
        if typesEqual(*lhsTarget, *rhsTarget) {
2387
            return Coercion::Identity;
2388
        }
2389
        return nil;
2390
    }
2391
    if let case Type::TraitObject { class: lhsClass, traitInfo: lhsTraitInfo, mutable: lhsMutable } = to {
2392
        if let case Type::Pointer { class: rhsClass, target: rhsTarget, mutable: rhsMutable } = from {
2393
            if not pointerClassesAssignable(lhsClass, rhsClass, self.inUnsafeContext)
2394
                or (lhsMutable and not rhsMutable)
2395
            {
2396
                return nil;
2397
            }
2398
            if let inst = findInstance(self, lhsTraitInfo, *rhsTarget) {
2399
                return Coercion::TraitObject { traitInfo: lhsTraitInfo, inst };
2400
            }
2401
        }
2402
        if let case Type::TraitObject { class: rhsClass, traitInfo: rhsTraitInfo, mutable: rhsMutable } = from {
2403
            if not pointerClassesAssignable(lhsClass, rhsClass, self.inUnsafeContext)
2404
                or lhsTraitInfo <> rhsTraitInfo
2405
            {
2406
                return nil;
2407
            }
2408
            if lhsMutable and not rhsMutable {
2409
                return nil;
2410
            }
2411
            return Coercion::Identity;
2412
        }
2413
        return nil;
2414
    }
2415
    if let case Type::Slice { class: lhsClass, item: lhsItem, mutable: lhsMutable } = to {
2416
        let case Type::Slice { class: rhsClass, item: rhsItem, mutable: rhsMutable } = from
2417
            else return nil;
2418
        if not pointerClassesAssignable(lhsClass, rhsClass, self.inUnsafeContext)
2419
            or (lhsMutable and not rhsMutable)
2420
        {
2421
            return nil;
2422
        }
2423
        // Allow coercion from `*[T]` to `*[opaque]`, and mutable counterparts.
2424
        if *lhsItem == Type::Opaque {
2425
            return Coercion::Identity;
2426
        }
2427
        if typesEqual(*lhsItem, *rhsItem) {
2428
            return Coercion::Identity;
2429
        }
2430
        return nil;
2431
    }
2432
    match to {
2433
        case Type::Array(lhs) => {
2434
            let case Type::Array(rhs) = from
2435
                else return nil;
2436
2437
            if lhs.length <> rhs.length {
2438
                return nil;
2439
            }
2440
            // For array literals, check each element individually for
2441
            // assignability.
2442
            match rval.value {
2443
                case ast::NodeValue::ArrayLit(items) => {
2444
                    if rhs.length == 0 and lhs.length == 0 {
2445
                        return Coercion::Identity;
2446
                    }
2447
                    // TODO: This won't work, because we should be setting coercions
2448
                    // for every list item, but we don't. It's best to not have an
2449
                    // `isAssignable` function and just have one that records coercions.
2450
                    if isListAssignable(self, *lhs.item, items) {
2451
                        return Coercion::Identity;
2452
                    }
2453
                    return nil;
2454
                }
2455
                case ast::NodeValue::ArrayRepeatLit(repeat) => {
2456
                    return isAssignable(self, *lhs.item, *rhs.item, repeat.item);
2457
                }
2458
                else => {
2459
                    if typesEqual(*lhs.item, *rhs.item) {
2460
                        return Coercion::Identity;
2461
                    }
2462
                    return nil;
2463
                }
2464
            }
2465
        }
2466
2467
        case Type::Optional(inner) => {
2468
            if from == Type::Nil {
2469
                return Coercion::OptionalLift(to);
2470
            }
2471
            if let _ = isAssignable(self, *inner, from, rval) {
2472
                return Coercion::OptionalLift(to);
2473
            }
2474
            if let case Type::Optional(fromInner) = from {
2475
                return isAssignable(self, *inner, *fromInner, rval);
2476
            }
2477
            return nil;
2478
        }
2479
2480
        case Type::Fn(toInfo) => {
2481
            // Allow function type structural matching.
2482
            if let case Type::Fn(fromInfo) = from {
2483
                if fnTypeEqual(toInfo, fromInfo) or (
2484
                    toInfo.isUnsafe and not fromInfo.isUnsafe
2485
                    and fnSignatureEqual(toInfo, fromInfo)
2486
                ) {
2487
                    return Coercion::Identity;
2488
                }
2489
            }
2490
            return nil;
2491
        }
2492
        else => {
2493
            if isNumericType(to) and isNumericType(from) {
2494
                // Perform range validation at compile time if possible.
2495
                // For unsuffixed integer expressions (`Type::Int`), only
2496
                // validate literals directly written by the programmer.
2497
                // Folded results (e.g. `0 - 65`) may not fit the target
2498
                // type but are valid wrapping arithmetic at runtime.
2499
                if let value = constValueEntry(self, rval) {
2500
                    if from <> Type::Int or isIntegerLiteralExpr(rval) {
2501
                        if validateConstIntRange(value, to) {
2502
                            return Coercion::Identity;
2503
                        }
2504
                        return nil;
2505
                    }
2506
                    // Folded constant expression (e.g. `1 + 2`): if the
2507
                    // result fits the target, use identity. Otherwise allow
2508
                    // wrapping via numeric cast.
2509
                    if validateConstIntRange(value, to) {
2510
                        return Coercion::Identity;
2511
                    }
2512
                }
2513
                // Allow unsuffixed integer expressions to be inferred from context.
2514
                if from == Type::Int {
2515
                    return Coercion::NumericCast { from, to };
2516
                }
2517
                // Non-constant numeric values require an explicit cast.
2518
                return nil;
2519
            }
2520
        }
2521
    }
2522
    return nil;
2523
}
2524
2525
/// Check if two function type descriptors are structurally equivalent.
2526
fn fnTypeEqual(a: &FnType, b: &FnType) -> bool {
2527
    if a.isUnsafe <> b.isUnsafe {
2528
        return false;
2529
    }
2530
    return fnSignatureEqual(a, b);
2531
}
2532
2533
/// Compare parameter, return, and error types of functions.
2534
fn fnSignatureEqual(a: &FnType, b: &FnType) -> bool {
2535
    if a.regions <> b.regions {
2536
        return false;
2537
    }
2538
    if a.paramTypes.len <> b.paramTypes.len {
2539
        return false;
2540
    }
2541
    if a.throwList.len <> b.throwList.len {
2542
        return false;
2543
    }
2544
    if not typesEqual(*a.returnType, *b.returnType) {
2545
        return false;
2546
    }
2547
    for i in 0..a.paramTypes.len {
2548
        if not typesEqual(*a.paramTypes[i], *b.paramTypes[i]) {
2549
            return false;
2550
        }
2551
    }
2552
    for i in 0..a.throwList.len {
2553
        if not typesEqual(*a.throwList[i], *b.throwList[i]) {
2554
            return false;
2555
        }
2556
    }
2557
    return true;
2558
}
2559
2560
/// Check if two types are structurally equal.
2561
export fn typesEqual(a: Type, b: Type) -> bool {
2562
    // Nominal and trait types compare by descriptor identity.
2563
    if a == b {
2564
        return true;
2565
    }
2566
    if let case Type::Pointer { class: aClass, target: aTarget, mutable: aMutable } = a {
2567
        let case Type::Pointer { class: bClass, target: bTarget, mutable: bMutable } = b
2568
            else return false;
2569
        return aClass == bClass and aMutable == bMutable
2570
            and typesEqual(*aTarget, *bTarget);
2571
    }
2572
    if let case Type::Slice { class: aClass, item: aItem, mutable: aMutable } = a {
2573
        let case Type::Slice { class: bClass, item: bItem, mutable: bMutable } = b
2574
            else return false;
2575
        return aClass == bClass and aMutable == bMutable
2576
            and typesEqual(*aItem, *bItem);
2577
    }
2578
    match a {
2579
        case Type::Cell { class, payload } => {
2580
            let case Type::Cell { class: otherClass, payload: other } = b else return false;
2581
            return class == otherClass and typesEqual(*payload, *other);
2582
        }
2583
        case Type::Array(aa) => {
2584
            let case Type::Array(ab) = b else return false;
2585
            return aa.length == ab.length and typesEqual(*aa.item, *ab.item);
2586
        }
2587
        case Type::Optional(oa) => {
2588
            let case Type::Optional(ob) = b else return false;
2589
            return typesEqual(*oa, *ob);
2590
        }
2591
        case Type::Fn(fa) => {
2592
            let case Type::Fn(fb) = b else return false;
2593
            return fnTypeEqual(fa, fb);
2594
        }
2595
        else => return false,
2596
    }
2597
}
2598
2599
/// Compare types after lexical region arguments are erased.
2600
/// Nominal types retain their source declaration identity.
2601
export unsafe fn erasedTypesEqual(a: Type, b: Type) -> bool {
2602
    if typesEqual(a, b) {
2603
        return true;
2604
    }
2605
    match a {
2606
        case Type::Cell { class, payload } => {
2607
            let case Type::Cell { class: otherClass, payload: other } = b else return false;
2608
            return erasedClassesEqual(class, otherClass) and erasedTypesEqual(*payload, *other);
2609
        }
2610
        case Type::Session(_) => {
2611
            let case Type::Session(_) = b else return false;
2612
            return true;
2613
        }
2614
        case Type::Nominal(left) => {
2615
            let case Type::Nominal(right) = b else return false;
2616
            let mut leftBase = left;
2617
            let mut rightBase = right;
2618
            if let app = nominalApplication(left) {
2619
                set leftBase = app.base;
2620
            }
2621
            if let app = nominalApplication(right) {
2622
                set rightBase = app.base;
2623
            }
2624
            return leftBase == rightBase;
2625
        }
2626
        case Type::Pointer { class, target, mutable } => {
2627
            let case Type::Pointer { class: otherClass, target: other, mutable: otherMutable } = b
2628
                else return false;
2629
            return erasedClassesEqual(class, otherClass) and mutable == otherMutable
2630
                and erasedTypesEqual(*target, *other);
2631
        }
2632
        case Type::Slice { class, item, mutable } => {
2633
            let case Type::Slice { class: otherClass, item: other, mutable: otherMutable } = b
2634
                else return false;
2635
            return erasedClassesEqual(class, otherClass) and mutable == otherMutable
2636
                and erasedTypesEqual(*item, *other);
2637
        }
2638
        case Type::TraitObject { class, traitInfo, mutable } => {
2639
            let case Type::TraitObject { class: otherClass, traitInfo: other, mutable: otherMutable } = b
2640
                else return false;
2641
            return erasedClassesEqual(class, otherClass) and mutable == otherMutable and traitInfo == other;
2642
        }
2643
        case Type::Array(left) => {
2644
            let case Type::Array(right) = b else return false;
2645
            return left.length == right.length and erasedTypesEqual(*left.item, *right.item);
2646
        }
2647
        case Type::Optional(left) => {
2648
            let case Type::Optional(right) = b else return false;
2649
            return erasedTypesEqual(*left, *right);
2650
        }
2651
        case Type::Fn(left) => {
2652
            let case Type::Fn(right) = b else return false;
2653
            if left.isUnsafe <> right.isUnsafe or left.paramTypes.len <> right.paramTypes.len
2654
                or left.throwList.len <> right.throwList.len {
2655
                return false;
2656
            }
2657
            for ty, i in left.paramTypes {
2658
                if not erasedTypesEqual(*ty, *right.paramTypes[i]) {
2659
                    return false;
2660
                }
2661
            }
2662
            for ty, i in left.throwList {
2663
                if not erasedTypesEqual(*ty, *right.throwList[i]) {
2664
                    return false;
2665
                }
2666
            }
2667
            return erasedTypesEqual(*left.returnType, *right.returnType);
2668
        }
2669
        else => return false,
2670
    }
2671
}
2672
2673
/// Compare pointer classes without lexical region identities.
2674
fn erasedClassesEqual(a: types::PointerClass, b: types::PointerClass) -> bool {
2675
    return a == b or (types::isReference(a) and types::isReference(b));
2676
}
2677
2678
/// Require distinct runtime tags for errors with different source types.
2679
unsafe fn validateErrorTag 'arena (self: &mut Resolver 'arena, node: *ast::Node, ty: Type, errors: *[*Type]) throws (ResolveError) {
2680
    for other in errors {
2681
        if not typesEqual(ty, *other) and erasedTypesEqual(ty, *other) {
2682
            throw emitError(self, node, ErrorKind::AmbiguousRegionalError);
2683
        }
2684
    }
2685
}
2686
2687
/// Return whether `ty` is a direct reference.
2688
export fn isRefType(ty: Type) -> bool {
2689
    match ty {
2690
        case Type::Cell { class, .. } => return types::isReference(class),
2691
        case Type::Pointer { class, .. } => return types::isReference(class),
2692
        case Type::Slice { class, .. } => return types::isReference(class),
2693
        case Type::TraitObject { class, .. } => return types::isReference(class),
2694
        else => return false,
2695
    }
2696
}
2697
2698
/// Get the region of a direct named reference.
2699
fn referenceRegion(ty: Type) -> ?*unsafe types::Region {
2700
    let mut class = types::PointerClass::Ref;
2701
    match ty {
2702
        case Type::Cell { class: cellClass, .. } => set class = cellClass,
2703
        case Type::Pointer { class: pointerClass, .. } => set class = pointerClass,
2704
        case Type::Slice { class: sliceClass, .. } => set class = sliceClass,
2705
        case Type::TraitObject { class: objectClass, .. } => set class = objectClass,
2706
        else => return nil,
2707
    }
2708
    if let case types::PointerClass::Region(region) = class {
2709
        return region;
2710
    }
2711
    return nil;
2712
}
2713
2714
/// Require every free region in a value type to remain in lexical scope.
2715
unsafe fn validateRegionDependencies 'arena (self: &mut Resolver 'arena, node: *ast::Node, ty: Type)
2716
    throws (ResolveError)
2717
{
2718
    try validateRegionStorage(self, node, ty, nil);
2719
}
2720
2721
/// Check a dependency against storage lifetime or current lexical visibility.
2722
unsafe fn regionCoversStorage(
2723
    scope: ?*RegionScope, dependency: *unsafe types::Region, destination: ?*unsafe types::Region
2724
) -> bool {
2725
    if let region = destination {
2726
        return types::regionContains(dependency, region);
2727
    }
2728
    return regionInScope(scope, dependency);
2729
}
2730
2731
/// Require stored references to cover the lifetime of checked destination storage.
2732
unsafe fn validateRegionalStore 'arena (self: &mut Resolver 'arena, place: *ast::Node, value: *ast::Node, ty: Type)
2733
    throws (ResolveError)
2734
{
2735
    if let case types::PointerClass::Region(region) = addressStorageClass(self, place) {
2736
        try validateRegionStorage(self, value, ty, region);
2737
    }
2738
}
2739
2740
/// Require all type dependencies to cover the destination or active lexical scope.
2741
unsafe fn validateRegionStorage 'arena (
2742
    self: &mut Resolver 'arena, node: *ast::Node, ty: Type, destination: ?*unsafe types::Region
2743
)
2744
    throws (ResolveError)
2745
{
2746
    if let case Type::Session(region) = ty {
2747
        if not regionCoversStorage(self.regionScope, region, destination) {
2748
            throw emitError(self, node, ErrorKind::RegionEscape(region.name));
2749
        }
2750
    }
2751
    if let region = referenceRegion(ty) {
2752
        if not regionCoversStorage(self.regionScope, region, destination) {
2753
            throw emitError(self, node, ErrorKind::RegionEscape(region.name));
2754
        }
2755
    }
2756
    match ty {
2757
        case Type::Pointer { target, .. } => try validateRegionStorage(self, node, *target, destination),
2758
        case Type::Slice { item, .. } => try validateRegionStorage(self, node, *item, destination),
2759
        case Type::Cell { payload, .. } => try validateRegionStorage(self, node, *payload, destination),
2760
        case Type::Array(array) => try validateRegionStorage(self, node, *array.item, destination),
2761
        case Type::Optional(inner) => try validateRegionStorage(self, node, *inner, destination),
2762
        case Type::Nominal(info) => {
2763
            if let applied = nominalApplication(info) {
2764
                for region in applied.arguments {
2765
                    if not regionCoversStorage(self.regionScope, region, destination) {
2766
                        throw emitError(self, node, ErrorKind::RegionEscape(region.name));
2767
                    }
2768
                }
2769
            }
2770
        }
2771
        case Type::Fn(info) => {
2772
            if info.regions <> nil {
2773
                return;
2774
            }
2775
            for parameter in info.paramTypes {
2776
                try validateRegionStorage(self, node, *parameter, destination);
2777
            }
2778
            for error in info.throwList {
2779
                try validateRegionStorage(self, node, *error, destination);
2780
            }
2781
            try validateRegionStorage(self, node, *info.returnType, destination);
2782
        }
2783
        else => {
2784
        },
2785
    }
2786
}
2787
2788
/// Return whether a type has an explicit region dependency.
2789
unsafe fn containsRegion(ty: Type) -> bool {
2790
    match ty {
2791
        case Type::Cell { class, payload } => {
2792
            if let case types::PointerClass::Region(_) = class {
2793
                return true;
2794
            }
2795
            return containsRegion(*payload);
2796
        }
2797
        case Type::Session(_) => return true,
2798
        case Type::Pointer { class, target, .. } => {
2799
            if let case types::PointerClass::Region(_) = class {
2800
                return true;
2801
            }
2802
            return containsRegion(*target);
2803
        }
2804
        case Type::Slice { class, item, .. } => {
2805
            if let case types::PointerClass::Region(_) = class {
2806
                return true;
2807
            }
2808
            return containsRegion(*item);
2809
        }
2810
        case Type::TraitObject { class, .. } => {
2811
            if let case types::PointerClass::Region(_) = class {
2812
                return true;
2813
            }
2814
            return false;
2815
        }
2816
        case Type::Array(array) => return containsRegion(*array.item),
2817
        case Type::Optional(inner) => return containsRegion(*inner),
2818
        case Type::Fn(info) => {
2819
            if info.regions <> nil or containsRegion(*info.returnType) {
2820
                return true;
2821
            }
2822
            for param in info.paramTypes {
2823
                if containsRegion(*param) {
2824
                    return true;
2825
                }
2826
            }
2827
            for error in info.throwList {
2828
                if containsRegion(*error) {
2829
                    return true;
2830
                }
2831
            }
2832
            return false;
2833
        }
2834
        case Type::Nominal(info) => return nominalApplication(info) <> nil,
2835
        else => return false,
2836
    }
2837
}
2838
2839
/// Return whether a stored type contains a reference without a named region.
2840
unsafe fn containsUnscopedRef(ty: Type) -> bool {
2841
    if isRefType(ty) and referenceRegion(ty) == nil {
2842
        return true;
2843
    }
2844
    if let case Type::Pointer { target, .. } = ty {
2845
        return containsUnscopedRef(*target);
2846
    }
2847
    if let case Type::Slice { item, .. } = ty {
2848
        return containsUnscopedRef(*item);
2849
    }
2850
    match ty {
2851
        case Type::Cell { payload, .. } => return containsUnscopedRef(*payload),
2852
        case Type::Array(array) => return containsUnscopedRef(*array.item),
2853
        case Type::Optional(inner) => return containsUnscopedRef(*inner),
2854
        case Type::Fn(info) => return info.regions <> nil,
2855
        // Nominal declarations validate their own fields and variants.
2856
        // Treating them as leaves also terminates recursive pointer types.
2857
        case Type::Nominal(_) => return false,
2858
        else => return false,
2859
    }
2860
}
2861
2862
/// Return whether `ty` may be duplicated implicitly.
2863
export unsafe fn isCopy(ty: Type) -> bool {
2864
    match ty {
2865
        case Type::Session(_) => return false,
2866
        case Type::Pointer { class, mutable, .. } =>
2867
            return class == types::PointerClass::Unsafe or not mutable,
2868
        case Type::Slice { class, mutable, .. } =>
2869
            return class == types::PointerClass::Unsafe or not mutable,
2870
        case Type::TraitObject { class, mutable, .. } =>
2871
            return class == types::PointerClass::Unsafe or not mutable,
2872
        case Type::Array(array) => return isCopy(*array.item),
2873
        case Type::Optional(inner) => return isCopy(*inner),
2874
        case Type::Nominal(NominalType::Record(recInfo)) => return recInfo.declaredCopy,
2875
        case Type::Nominal(NominalType::Union(unionType)) => return unionType.declaredCopy,
2876
        case Type::Nominal(NominalType::Application(applied)) => return isCopy(Type::Nominal(applied.base)),
2877
        case Type::Nominal(NominalType::Placeholder(_)), Type::Nominal(NominalType::Resolving(_)) => return false,
2878
        else => return true,
2879
    }
2880
}
2881
2882
/// Return whether a type must be consumed exactly once.
2883
export unsafe fn isLinear(ty: Type) -> bool {
2884
    match ty {
2885
        case Type::Nominal(NominalType::Application(applied)) => return isLinear(Type::Nominal(applied.base)),
2886
        case Type::Array(array) => return isLinear(*array.item),
2887
        case Type::Optional(inner) => return isLinear(*inner),
2888
        case Type::Nominal(NominalType::Record(recInfo)) => {
2889
            if recInfo.declaredLinear {
2890
                return true;
2891
            }
2892
            for field in recInfo.fields {
2893
                if isLinear(field.fieldType) {
2894
                    return true;
2895
                }
2896
            }
2897
            return false;
2898
        }
2899
        case Type::Nominal(NominalType::Union(unionType)) => {
2900
            if unionType.declaredLinear {
2901
                return true;
2902
            }
2903
            for variant in unionType.variants {
2904
                if isLinear(variant.valueType) {
2905
                    return true;
2906
                }
2907
            }
2908
            return false;
2909
        }
2910
        else => return false,
2911
    }
2912
}
2913
2914
/// Return whether a by-value use moves `ty`.
2915
unsafe fn isMoveOnly(ty: Type) -> bool {
2916
    return not isCopy(ty);
2917
}
2918
2919
/// Return whether `ty` is a direct unsafe pointer-like value.
2920
fn isUnsafePointerType(ty: Type) -> bool {
2921
    match ty {
2922
        case Type::Cell { class: types::PointerClass::Unsafe, .. },
2923
             Type::Pointer { class: types::PointerClass::Unsafe, .. },
2924
             Type::Slice { class: types::PointerClass::Unsafe, .. },
2925
             Type::TraitObject { class: types::PointerClass::Unsafe, .. } => return true,
2926
        else => return false,
2927
    }
2928
}
2929
2930
/// Get the record info from a record type.
2931
export unsafe fn getRecord(ty: Type) -> ?RecordType {
2932
    let case Type::Nominal(NominalType::Record(recInfo)) = ty else return nil;
2933
    return recInfo;
2934
}
2935
2936
/// Auto-dereference a type: if it's a pointer, return the target type.
2937
export fn autoDeref(ty: Type) -> Type {
2938
    if let case Type::Pointer { target, .. } = ty {
2939
        return *target;
2940
    }
2941
    return ty;
2942
}
2943
2944
/// Get field info for a record-like type (records, slices) by field index.
2945
export unsafe fn getRecordField(ty: Type, index: u32) -> ?RecordField {
2946
    if let case Type::Slice { class, item, mutable } = ty {
2947
        match index {
2948
            case 0 => return RecordField {
2949
                name: PTR_FIELD,
2950
                fieldType: Type::Pointer { class, target: item, mutable },
2951
                offset: 0,
2952
            },
2953
            case 1 => return RecordField {
2954
                name: LEN_FIELD,
2955
                fieldType: Type::U32,
2956
                offset: PTR_SIZE as i32,
2957
            },
2958
            case 2 => return RecordField {
2959
                name: CAP_FIELD,
2960
                fieldType: Type::U32,
2961
                offset: PTR_SIZE as i32 + 4,
2962
            },
2963
            else => return nil,
2964
        }
2965
    }
2966
    if let case Type::Nominal(NominalType::Record(recInfo)) = ty;
2967
        index < recInfo.fields.len
2968
    {
2969
        return recInfo.fields[index];
2970
    }
2971
    return nil;
2972
}
2973
2974
/// Check if the two types can be compared for equality.
2975
unsafe fn isComparable(left: Type, right: Type) -> bool {
2976
    if left == Type::Unknown or right == Type::Unknown {
2977
        return false;
2978
    }
2979
    if left == right {
2980
        return true;
2981
    }
2982
    // Comparisons with optionals.
2983
    if let case Type::Optional(l) = left {
2984
        if let case Type::Optional(r) = right {
2985
            return isComparable(*l, *r);
2986
        } else if right == Type::Nil {
2987
            return true;
2988
        }
2989
        return isComparable(*l, right);
2990
    } else if let case Type::Optional(_) = right {
2991
        return isComparable(right, left); // Flip order.
2992
    }
2993
    // Pointer comparisons ignore mutability.
2994
    if let case Type::Pointer { target: lTarget, .. } = left {
2995
        if let case Type::Pointer { target: rTarget, .. } = right {
2996
            return typesEqual(*lTarget, *rTarget);
2997
        }
2998
    }
2999
    // Numeric types.
3000
    if isNumericType(left) and isNumericType(right) {
3001
        return true;
3002
    }
3003
    return false;
3004
}
3005
3006
/// Check if the `from` type is assignable to the `to` type, and return a
3007
/// coercion plan if so, or throw an error if not.
3008
unsafe fn expectAssignable 'arena (self: &mut Resolver 'arena, to: Type, source: Type, site: *ast::Node) -> Coercion throws (ResolveError) {
3009
    let from = assignableValueType(self, site, source);
3010
    if isRefType(to) and isUnsafePointerType(from) {
3011
        try requireUnsafe(self, site);
3012
    }
3013
    // Ensure any nested nominal types are resolved before checking assignability.
3014
    try ensureTypeResolved(self, to, site);
3015
    if let coercion = isAssignable(self, to, from, site) {
3016
        return setNodeCoercion(self, site, coercion);
3017
    }
3018
    throw emitTypeMismatch(self, site, TypeMismatch {
3019
        expected: to,
3020
        actual: from,
3021
    });
3022
}
3023
3024
/// Check that a type is optional, otherwise throw an error.
3025
unsafe fn checkOptional 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> *Type
3026
    throws (ResolveError)
3027
{
3028
    if let case Type::Optional(inner) = try infer(self, node) {
3029
        return inner;
3030
    }
3031
    throw emitError(self, node, ErrorKind::ExpectedOptional);
3032
}
3033
3034
/// Check that a node's type is equal to the expected type.
3035
unsafe fn checkEqual 'arena (self: &mut Resolver 'arena, node: *ast::Node, expected: Type) -> Type
3036
    throws (ResolveError)
3037
{
3038
    let actualTy = try visit(self, node, expected);
3039
    if actualTy <> expected {
3040
        throw emitTypeMismatch(self, node, TypeMismatch { expected, actual: actualTy });
3041
    }
3042
    return actualTy;
3043
}
3044
3045
/// Bind an identifier in the given scope.
3046
unsafe fn bindIdent 'arena (
3047
    self: &mut Resolver 'arena,
3048
    name: *[u8],
3049
    owner: *ast::Node,
3050
    data: SymbolData,
3051
    attrs: u32,
3052
    scope: *unsafe mut Scope
3053
) -> *unsafe mut Symbol throws (ResolveError) {
3054
    let sym = allocSymbol(self, data, name, owner, attrs);
3055
    try addSymbolToScope(self, sym, scope, owner);
3056
    setNodeSymbol(self, owner, sym);
3057
3058
    return sym;
3059
}
3060
3061
/// Add a symbol to the given scope.
3062
unsafe fn addSymbolToScope 'arena (self: &mut Resolver 'arena, sym: *unsafe mut Symbol, scope: *unsafe mut Scope, site: *ast::Node) throws (ResolveError) {
3063
    for i in 0..scope.symbolsLen {
3064
        if scope.symbols[i].name == sym.name {
3065
            throw emitError(self, site, ErrorKind::DuplicateBinding(sym.name));
3066
        }
3067
    }
3068
    if scope.symbolsLen >= scope.symbols.len {
3069
        throw emitError(self, site, ErrorKind::SymbolOverflow);
3070
    }
3071
    // Preserve the defining module when importing an existing symbol into
3072
    // another module's scope.
3073
    if sym.moduleId == nil {
3074
        if let modId = scope.moduleId {
3075
            set sym.moduleId = modId;
3076
        }
3077
    }
3078
    set scope.symbols[scope.symbolsLen] = sym;
3079
    set scope.symbolsLen += 1;
3080
}
3081
3082
/// Bind a value identifier in the current scope.
3083
/// Returns `nil` if the identifier is a placeholder (`_`).
3084
unsafe fn bindValueIdent 'arena (
3085
    self: &mut Resolver 'arena,
3086
    ident: *ast::Node,
3087
    owner: *ast::Node,
3088
    type: Type,
3089
    mutable: bool,
3090
    alignment: u32,
3091
    attrs: u32
3092
) -> ?*unsafe mut Symbol throws (ResolveError) {
3093
    if let case ast::NodeValue::Placeholder = ident.value {
3094
        setNodeType(self, owner, type);
3095
        return nil;
3096
    }
3097
    let name = try nodeName(self, ident);
3098
    let data = SymbolData::Value { mutable, alignment, type, addressTaken: false };
3099
    let scope = self.scope;
3100
    let sym = try bindIdent(self, name, owner, data, attrs, scope);
3101
    setNodeType(self, owner, type);
3102
    setNodeType(self, ident, type);
3103
3104
    // Track number of local bindings for lowering stage.
3105
    if let owner = self.currentFnNode {
3106
        set self.nodeData.entries[owner.id].localCount += 1;
3107
    }
3108
    return sym;
3109
}
3110
3111
/// Bind a constant identifier in the current scope.
3112
unsafe fn bindConstIdent 'arena (
3113
    self: &mut Resolver 'arena,
3114
    ident: *ast::Node,
3115
    owner: *ast::Node,
3116
    type: Type,
3117
    val: ?ConstValue,
3118
    attrs: u32
3119
) -> *unsafe mut Symbol throws (ResolveError) {
3120
    let name = try nodeName(self, ident);
3121
    let data = SymbolData::Constant { type, value: val };
3122
    let scope = self.scope;
3123
    let sym = try bindIdent(self, name, owner, data, attrs, scope);
3124
    setNodeType(self, owner, type);
3125
    setNodeType(self, ident, type);
3126
3127
    return sym;
3128
}
3129
3130
/// Bind a module identifier in the given scope.
3131
/// This is used when declaring modules with `mod` or
3132
/// importing modules with `use`.
3133
unsafe fn bindModuleIdent 'arena (
3134
    self: &mut Resolver 'arena,
3135
    entry: *module::ModuleEntry,
3136
    scope: *unsafe mut Scope,
3137
    owner: *ast::Node,
3138
    attrs: u32,
3139
    bindingScope: *unsafe mut Scope
3140
) -> *unsafe mut Symbol throws (ResolveError) {
3141
    let data = SymbolData::Module { entry, scope };
3142
    let name = entry.name;
3143
3144
    return try bindIdent(self, name, owner, data, attrs, bindingScope);
3145
}
3146
3147
/// Bind a type identifier in the current scope.
3148
unsafe fn bindTypeIdent 'arena (
3149
    self: &mut Resolver 'arena,
3150
    ident: *ast::Node,
3151
    owner: *ast::Node,
3152
    type: *unsafe mut NominalType,
3153
    attrs: u32
3154
) -> *unsafe mut Symbol throws (ResolveError) {
3155
    let name = try nodeName(self, ident);
3156
    let data = SymbolData::Type(type);
3157
    let scope = self.scope;
3158
    return try bindIdent(self, name, owner, data, attrs, scope);
3159
}
3160
3161
/// Predicate that matches any symbol.
3162
fn isAnySymbol(_sym: *unsafe mut Symbol) -> bool {
3163
    return true;
3164
}
3165
3166
/// Predicate that matches value or constant symbols.
3167
unsafe fn isValueSymbol(sym: *unsafe mut Symbol) -> bool {
3168
    if let case SymbolData::Value { .. } = sym.data {
3169
        return true;
3170
    }
3171
    if let case SymbolData::Constant { .. } = sym.data {
3172
        return true;
3173
    }
3174
    return false;
3175
}
3176
3177
/// Predicate that matches type symbols.
3178
unsafe fn isTypeSymbol(sym: *unsafe mut Symbol) -> bool {
3179
    if let case SymbolData::Type(_) = sym.data {
3180
        return true;
3181
    }
3182
    return false;
3183
}
3184
3185
/// Find a symbol by name in a specific scope, filtered by a predicate.
3186
unsafe fn findInScope(scope: *unsafe Scope, name: *[u8], predicate: unsafe fn(*unsafe mut Symbol) -> bool) -> ?*unsafe mut Symbol {
3187
    for i in 0..scope.symbolsLen {
3188
        let sym = scope.symbols[i];
3189
        if sym.name == name and predicate(sym) {
3190
            return sym;
3191
        }
3192
    }
3193
    return nil;
3194
}
3195
3196
/// Find a symbol by name, traversing scopes upwards, filtered by a predicate.
3197
unsafe fn findInScopeRecursive(scope: *unsafe Scope, name: *[u8], predicate: unsafe fn(*unsafe mut Symbol) -> bool) -> ?*unsafe mut Symbol {
3198
    let mut curr = scope;
3199
    loop {
3200
        if let sym = findInScope(curr, name, predicate) {
3201
            return sym;
3202
        }
3203
        if let parent = curr.parent {
3204
            set curr = parent;
3205
        } else {
3206
            break;
3207
        }
3208
    }
3209
    return nil;
3210
}
3211
3212
/// Find a symbol by name in a specific scope (matches any symbol kind).
3213
export unsafe fn findSymbolInScope(scope: *unsafe Scope, name: *[u8]) -> ?*unsafe mut Symbol {
3214
    return findInScope(scope, name, isAnySymbol);
3215
}
3216
3217
/// Look up a value symbol by name, searching from the given scope outward.
3218
unsafe fn findValueSymbol(scope: *unsafe Scope, name: *[u8]) -> ?*unsafe mut Symbol {
3219
    return findInScopeRecursive(scope, name, isValueSymbol);
3220
}
3221
3222
/// Look up a type symbol by name, searching from the given scope outward.
3223
unsafe fn findTypeSymbol(scope: *unsafe Scope, name: *[u8]) -> ?*unsafe mut Symbol {
3224
    return findInScopeRecursive(scope, name, isTypeSymbol);
3225
}
3226
3227
/// Like `findValueSymbol`, but finds symbols of any kinds.
3228
unsafe fn findAnySymbol(scope: *unsafe Scope, name: *[u8]) -> ?*unsafe mut Symbol {
3229
    return findInScopeRecursive(scope, name, isAnySymbol);
3230
}
3231
3232
/// Flatten an identifier or scope access chain into an array of name segments.
3233
/// Examples: `fnord` -> `&["fnord"]`, `a::b::c` -> `&["a", "b", "c"]`.
3234
/// Return the number of segments written to the buffer.
3235
unsafe fn flattenPath 'arena (
3236
    self: &mut Resolver 'arena,
3237
    node: *ast::Node,
3238
    buf: &mut [*[u8]]
3239
) -> u32 throws (ResolveError) {
3240
    let mut out: u32 = 0;
3241
3242
    match node.value {
3243
        case ast::NodeValue::Ident(name) if name.len > 0 => {
3244
            assert buf.len >= 1, "flattenPath: invalid output buffer size";
3245
            set buf[0] = name;
3246
            set out = 1;
3247
        }
3248
        case ast::NodeValue::ScopeAccess(access) => {
3249
            // Recursively flatten parent path.
3250
            let parent = try flattenPath(self, access.parent, buf);
3251
            assert parent < buf.len, "flattenPath: invalid output buffer size";
3252
            let child = try nodeName(self, access.child);
3253
            set buf[parent] = child;
3254
            set out = parent + 1;
3255
        }
3256
        case ast::NodeValue::Super => {
3257
            // `super` is handled by scope adjustment in `checkSuperAccess`.
3258
            // Return empty prefix so the path continues from the next segment.
3259
            set out = 0;
3260
            return out;
3261
        }
3262
        else => {
3263
            // Fallthrough to error.
3264
        }
3265
    }
3266
    if out < 1 {
3267
        throw emitError(self, node, ErrorKind::InvalidIdentifier(node));
3268
    }
3269
    return out;
3270
}
3271
3272
/// Find the module ID for a given scope by walking up the scope chain until
3273
/// we hit the module's scope.
3274
unsafe fn findModuleForScope(scope: *unsafe Scope) -> ?u16 {
3275
    let mut s = scope;
3276
    loop {
3277
        if let id = s.moduleId {
3278
            return id;
3279
        }
3280
        if let parent = s.parent {
3281
            set s = parent;
3282
        } else {
3283
            return nil;
3284
        }
3285
    }
3286
}
3287
3288
/// Get the parent module scope for the current module.
3289
/// Returns the scope of the parent module, or `nil` if this is a root module.
3290
unsafe fn getParentModuleScope 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> ?*unsafe mut Scope throws (ResolveError) {
3291
    let currentMod = module::get(self.moduleGraph, self.currentMod)
3292
        else throw emitError(self, node, ErrorKind::Internal);
3293
    let parentId = currentMod.parent
3294
        else return nil; // No parent module.
3295
3296
    return self.moduleScopes[parentId as u32];
3297
}
3298
3299
/// Check if a node has `super` at its root (e.g. `super::x` or `super::Union::Variant`).
3300
/// Returns the parent scope and the original node so `flattenPath` can strip `super`.
3301
unsafe fn checkSuperAccess 'arena (
3302
    self: &mut Resolver 'arena,
3303
    node: *ast::Node
3304
) -> ?SuperAccessResult throws (ResolveError) {
3305
    // TODO: Maybe we should deal with `super` after the path is flattened.
3306
    if let case ast::NodeValue::ScopeAccess(access) = node.value {
3307
        // Direct super access: `super::x`.
3308
        if let case ast::NodeValue::Super = access.parent.value {
3309
            let parentScope = try getParentModuleScope(self, node)
3310
                else throw emitError(self, node, ErrorKind::InvalidModulePath);
3311
            return SuperAccessResult { scope: parentScope, child: node };
3312
        }
3313
        // Nested super access: `super::x::y`, check if parent path contains `super`.
3314
        if let _ = try checkSuperAccess(self, access.parent) {
3315
            let parentScope = try getParentModuleScope(self, node)
3316
                else throw emitError(self, node, ErrorKind::InvalidModulePath);
3317
            return SuperAccessResult { scope: parentScope, child: node };
3318
        }
3319
    }
3320
    return nil;
3321
}
3322
3323
/// Check if a symbol is accessible from the given scope.
3324
/// A symbol is accessible if:
3325
/// * It has the `export` attribute, OR
3326
/// * It's being accessed from within the module where it was defined.
3327
unsafe fn isSymbolVisible(sym: *unsafe Symbol, symScope: *unsafe Scope, fromScope: *unsafe Scope) -> bool {
3328
    // Public symbols are visible from anywhere.
3329
    if ast::hasAttribute(sym.attrs, ast::Attribute::Export) {
3330
        return true;
3331
    }
3332
    // In test mode, @test symbols are visible from anywhere
3333
    // so the test runner can reference them.
3334
    if ast::hasAttribute(sym.attrs, ast::Attribute::Test) {
3335
        return true;
3336
    }
3337
    // Private symbols are only visible from the same module.
3338
    let symModuleId = findModuleForScope(symScope);
3339
    let currentModuleId = findModuleForScope(fromScope);
3340
3341
    return symModuleId == currentModuleId;
3342
}
3343
3344
/// Resolve an access node (eg. `lang::resolver::MAX_ERRORS`) to a symbol,
3345
/// starting from the given scope.
3346
unsafe fn resolveAccess 'arena (
3347
    self: &mut Resolver 'arena,
3348
    node: *ast::Node,
3349
    access: ast::Access,
3350
    scope: *unsafe Scope
3351
) -> *unsafe mut Symbol throws (ResolveError) {
3352
    if let case ast::NodeValue::RegionApply { .. } = access.parent.value {
3353
        let ty = try infer(self, access.parent);
3354
        let case Type::Nominal(info) = ty else throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3355
        try ensureNominalResolved(self, info, access.parent);
3356
        let case NominalType::Union(body) = *info else throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3357
        let name = try nodeName(self, access.child);
3358
        let symbol = try resolveUnionVariantAccess(self, node, access, body, name);
3359
        setNodeType(self, node, ty);
3360
        return symbol;
3361
    }
3362
    // Handle `super` access by adjusting scope and node.
3363
    let mut startScope = scope;
3364
    let mut pathNode = node;
3365
    if let superAccess = try checkSuperAccess(self, node) {
3366
        set startScope = superAccess.scope;
3367
        set pathNode = superAccess.child;
3368
    }
3369
    // TODO: It doesn't make sense that `flattenPath` handles identifiers and scope access,
3370
    // while this function requires a scope access.
3371
    let mut buffer: [*[u8]; 32] = undefined;
3372
    let pathLen = try flattenPath(self, pathNode, &mut buffer[..]);
3373
3374
    return try resolvePath(self, node, access, &buffer[..pathLen], startScope);
3375
}
3376
3377
/// Resolve a path (eg. ["lang", "resolver", "MAX_ERRORS"]) to a symbol,
3378
/// starting from the given scope.
3379
unsafe fn resolvePath 'arena (
3380
    self: &mut Resolver 'arena,
3381
    node: *ast::Node,
3382
    access: ast::Access,
3383
    path: &[*[u8]],
3384
    scope: *unsafe Scope
3385
) -> *unsafe mut Symbol throws (ResolveError) {
3386
    assert path.len <> 0, "resolvePath: empty path";
3387
    // Start by finding the root of the path.
3388
    let root = path[0];
3389
    let sym = findInScopeRecursive(scope, root, isAnySymbol)
3390
        else throw emitError(self, node, ErrorKind::UnresolvedSymbol(root));
3391
3392
    // Check visibility for symbol.
3393
    if not isSymbolVisible(sym, scope, self.scope) {
3394
        throw emitError(self, node, ErrorKind::UnresolvedSymbol(root));
3395
    }
3396
    // End condition.
3397
    if path.len == 1 {
3398
        return sym;
3399
    }
3400
    // Otherwise, we need to enter the next scope with the path suffix.
3401
    match sym.data {
3402
        case SymbolData::Module { scope, .. } => {
3403
            return try resolvePath(self, node, access, &path[1..], scope);
3404
        }
3405
        case SymbolData::Type(ty) => {
3406
            // Lazily resolve union body if not yet done.
3407
            try ensureNominalResolved(self, ty, node);
3408
3409
            if let case NominalType::Union(unionType) = *ty {
3410
                // TODO: Recurse with variant so we consolidate everything.
3411
                if path.len > 2 {
3412
                    throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3413
                }
3414
                let variantName = path[1];
3415
                let variantSym = try resolveUnionVariantAccess(
3416
                    self, node, access, unionType, variantName
3417
                );
3418
                // TODO: This shouldn't be here.
3419
                setNodeType(self, node, Type::Nominal(ty));
3420
                return variantSym;
3421
            }
3422
        }
3423
        else => {} // Fallthrough.
3424
    }
3425
    throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3426
}
3427
3428
/// Resolve a module path (e.g., `foo::bar::baz`) to a module entry and scope.
3429
/// This traverses the module hierarchy, checking visibility at each step.
3430
unsafe fn resolveModulePath 'arena (
3431
    self: &mut Resolver 'arena,
3432
    module: *ast::Node
3433
) -> ResolvedModule throws (ResolveError) {
3434
    let mut startScope = self.scope;
3435
    let mut pathNode = module;
3436
3437
    // Handle `super` access.
3438
    if let superAccess = try checkSuperAccess(self, module) {
3439
        set startScope = superAccess.scope;
3440
        set pathNode = superAccess.child;
3441
    }
3442
    let mut pathBuf: [*[u8]; 16] = undefined;
3443
    let pathLen = try flattenPath(self, pathNode, &mut pathBuf[..]);
3444
    if pathLen == 0 {
3445
        throw emitError(self, module, ErrorKind::UnresolvedSymbol(""));
3446
    }
3447
    let parentName = pathBuf[0];
3448
3449
    // First, check if this is a sub-module of the start scope.
3450
    if let sym = findSymbolInScope(startScope, parentName) {
3451
        return try resolveModulePathRecursive(self, module, &pathBuf[1..pathLen], sym);
3452
    }
3453
    // Not a sub-module, so look in the global scope for a package root.
3454
    let sym = findSymbolInScope(self.pkgScope, parentName)
3455
        else throw emitError(self, module, ErrorKind::UnresolvedSymbol(parentName));
3456
3457
    return try resolveModulePathRecursive(self, module, &pathBuf[1..pathLen], sym);
3458
}
3459
3460
/// Recursively resolve the remaining path segments by traversing child modules.
3461
unsafe fn resolveModulePathRecursive 'arena (
3462
    self: &mut Resolver 'arena,
3463
    node: *ast::Node,
3464
    path: &[*[u8]],
3465
    sym: *unsafe Symbol
3466
) -> ResolvedModule throws (ResolveError) {
3467
    let case SymbolData::Module { entry, scope } = sym.data
3468
        else throw emitError(self, node, ErrorKind::Internal);
3469
3470
    if path.len == 0 {
3471
        return ResolvedModule { entry, scope };
3472
    }
3473
    let childName = path[0];
3474
    let childSym = findSymbolInScope(scope, childName)
3475
        else throw emitError(self, node, ErrorKind::UnresolvedSymbol(childName));
3476
3477
    if not isSymbolVisible(childSym, scope, self.scope) {
3478
        throw emitError(self, node, ErrorKind::UnresolvedSymbol(childName));
3479
    }
3480
    return try resolveModulePathRecursive(
3481
        self,
3482
        node,
3483
        &path[1..],
3484
        childSym
3485
    );
3486
}
3487
3488
/// Resolve a type name, which could be an identifier or scoped path.
3489
unsafe fn resolveTypeName 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> *unsafe NominalType throws (ResolveError) {
3490
    match node.value {
3491
        case ast::NodeValue::Ident(name) => {
3492
            let sym = findTypeSymbol(self.scope, name)
3493
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
3494
            let case SymbolData::Type(ty) = sym.data
3495
                else throw emitError(self, node, ErrorKind::Internal);
3496
3497
            setNodeSymbol(self, node, sym);
3498
3499
            return ty;
3500
        }
3501
        case ast::NodeValue::ScopeAccess(access) => {
3502
            let scope = self.scope;
3503
            let sym = try resolveAccess(self, node, access, scope);
3504
            let case SymbolData::Type(ty) = sym.data
3505
                else throw emitError(self, node, ErrorKind::Internal);
3506
3507
            setNodeSymbol(self, node, sym);
3508
3509
            return ty;
3510
        }
3511
        else => panic "resolveTypeName: unsupported node value",
3512
    }
3513
}
3514
3515
/// Visit a top-level declaration in the declaration phase.
3516
/// This binds all names and analyzes signatures, types, and initializers.
3517
/// Function bodies are deferred to the definition phase.
3518
///
3519
/// Nb. User-defined types are already handled by this point.
3520
unsafe fn visitDecl 'arena (self: &mut Resolver 'arena, node: *ast::Node) throws (ResolveError) {
3521
    match node.value {
3522
        case ast::NodeValue::FnDecl(_),
3523
             ast::NodeValue::ConstDecl(_),
3524
             ast::NodeValue::Mod(_),
3525
             ast::NodeValue::Use(_) => {
3526
            // Handled in previous passes.
3527
        }
3528
        case ast::NodeValue::StaticDecl(_) => {
3529
            try infer(self, node);
3530
        }
3531
        case ast::NodeValue::InstanceDecl { traitName, targetType, regions, methods } => {
3532
            try resolveInstanceDecl(self, node, traitName, targetType, regions, methods);
3533
        }
3534
        case ast::NodeValue::MethodDecl {
3535
            ..
3536
        } => {
3537
            try resolveMethodDecl(self, node);
3538
        }
3539
        else => {
3540
            // Ignore non-declaration nodes.
3541
        }
3542
    }
3543
}
3544
3545
/// Require an unsafe function or block.
3546
unsafe fn requireUnsafe 'arena (self: &mut Resolver 'arena, node: *ast::Node) throws (ResolveError) {
3547
    if not self.inUnsafeContext {
3548
        throw emitError(self, node, ErrorKind::UnsafeOperation);
3549
    }
3550
}
3551
3552
/// Require an unsafe context for any access to an unsafe static.
3553
unsafe fn checkStaticAccess 'arena (self: &mut Resolver 'arena, node: *ast::Node, sym: &Symbol)
3554
    throws (ResolveError)
3555
{
3556
    if let case ast::NodeValue::StaticDecl(_) = sym.node.value {
3557
        if ast::hasAttribute(sym.attrs, ast::Attribute::Unsafe) {
3558
            try requireUnsafe(self, node);
3559
        }
3560
    }
3561
}
3562
3563
/// Reject calls from safe code through unsafe function types.
3564
unsafe fn checkUnsafeCall 'arena (self: &mut Resolver 'arena, node: *ast::Node, info: *FnType)
3565
    throws (ResolveError)
3566
{
3567
    if info.isUnsafe and not self.inUnsafeContext {
3568
        throw emitError(self, node, ErrorKind::UnsafeCall);
3569
    }
3570
}
3571
3572
/// Visit a top-level definition, recursing into sub-modules.
3573
unsafe fn visitDef 'arena (self: &mut Resolver 'arena, node: *ast::Node) throws (ResolveError) {
3574
    match node.value {
3575
        case ast::NodeValue::FnDecl(decl) => {
3576
            try resolveFnDeclBody(self, node, decl) catch {
3577
                return;
3578
            };
3579
        }
3580
        case ast::NodeValue::Mod(decl) => {
3581
            let modName = try nodeName(self, decl.name);
3582
            if not shouldAnalyzeModule(self, decl.attrs, modName) {
3583
                return;
3584
            }
3585
            let submod = try enterSubModule(self, modName, node);
3586
            let case ast::NodeValue::Block(block) = submod.root.value
3587
                else panic "visitDef: expected block for module root";
3588
            try resolveModuleDefs(self, &block) catch e {
3589
                exitModuleScope(self, submod);
3590
                throw e;
3591
            };
3592
            exitModuleScope(self, submod);
3593
        }
3594
        case ast::NodeValue::RecordDecl(_),
3595
             ast::NodeValue::UnionDecl(_),
3596
             ast::NodeValue::Use(_),
3597
             ast::NodeValue::TraitDecl { .. } => {
3598
            // Skip: already analyzed in declaration phase.
3599
        }
3600
        case ast::NodeValue::InstanceDecl { methods, .. } => {
3601
            try resolveInstanceMethodBodies(self, methods);
3602
        }
3603
        case ast::NodeValue::MethodDecl {
3604
            ..
3605
        } => {
3606
            try resolveMethodBody(self, node);
3607
        }
3608
        else => {
3609
            // FIXME: This allows module-level statements that should
3610
            // normally only be valid inside function bodies. We currently
3611
            // need this because of how tests are written, but it should
3612
            // be eventually removed.
3613
            try infer(self, node) catch {
3614
                return;
3615
            };
3616
        }
3617
    }
3618
}
3619
3620
/// Try to infer a node's type.
3621
unsafe fn infer 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> Type throws (ResolveError) {
3622
    return try visit(self, node, Type::Unknown);
3623
}
3624
3625
/// Permit named reference dependencies and direct call-scoped or local references.
3626
unsafe fn validateValueTypeReferences 'arena (self: &mut Resolver 'arena, node: *ast::Node, ty: Type)
3627
    throws (ResolveError)
3628
{
3629
    try validateRegionDependencies(self, node, ty);
3630
    if let case Type::Fn(info) = ty; info.regions == nil {
3631
        return;
3632
    }
3633
    if isRefType(ty) {
3634
        if let case Type::Pointer { target, .. } = ty {
3635
            if containsUnscopedRef(*target) {
3636
                throw emitError(self, node, ErrorKind::InvalidRefPosition);
3637
            }
3638
        } else if let case Type::Slice { item, .. } = ty {
3639
            if containsUnscopedRef(*item) {
3640
                throw emitError(self, node, ErrorKind::InvalidRefPosition);
3641
            }
3642
        }
3643
    } else if containsUnscopedRef(ty) {
3644
        throw emitError(self, node, ErrorKind::InvalidRefPosition);
3645
    }
3646
}
3647
3648
/// Require a type that may be stored or escape a call.
3649
unsafe fn ensureStorableType 'arena (self: &mut Resolver 'arena, node: *ast::Node, ty: Type)
3650
    throws (ResolveError)
3651
{
3652
    try validateRegionDependencies(self, node, ty);
3653
    if containsUnscopedRef(ty) {
3654
        throw emitError(self, node, ErrorKind::InvalidRefPosition);
3655
    }
3656
}
3657
3658
/// Resolve a type signature node.
3659
unsafe fn resolveValueType 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> Type throws (ResolveError) {
3660
    let ty = try visit(self, node, Type::Unknown);
3661
    if let case Type::Nominal(info) = ty {
3662
        try requireNominalArguments(self, info, node);
3663
    }
3664
    // Opaque value types are not allowed.
3665
    if ty == Type::Opaque {
3666
        throw emitError(self, node, ErrorKind::OpaqueTypeNotAllowed);
3667
    }
3668
    try validateValueTypeReferences(self, node, ty);
3669
    return ty;
3670
}
3671
3672
/// Analyze a node's type and check that it can be assigned to the expected type.
3673
unsafe fn checkAssignable 'arena (self: &mut Resolver 'arena, node: *ast::Node, expected: Type) -> Type throws (ResolveError) {
3674
    let actual = try visit(self, node, expected);
3675
    let _ = try expectAssignable(self, expected, actual, node);
3676
    if isRefType(expected) and isMutablePointerLike(expected) and isMutablePointerLike(actual) {
3677
        if not try canMutateThrough(self, node) {
3678
            throw emitError(self, node, ErrorKind::ImmutableBinding);
3679
        }
3680
    }
3681
    return actual;
3682
}
3683
3684
/// Analyze a node and propagate the resolved type.
3685
/// The `hint` parameter provides type context for inference and validation.
3686
/// When `nil`, the type must be inferred from the expression itself.
3687
unsafe fn visit 'arena (self: &mut Resolver 'arena, node: *ast::Node, hint: Type) -> Type
3688
    throws (ResolveError)
3689
{
3690
    if let ty = typeFor(self, node) {
3691
        // An optional context completes a nil expression's storage type.
3692
        if ty <> Type::Nil or not isOptionalType(hint) {
3693
            return ty;
3694
        }
3695
    }
3696
    match node.value {
3697
        case ast::NodeValue::Ident(name) => {
3698
            let sym = findAnySymbol(self.scope, name)
3699
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
3700
            try checkStaticAccess(self, node, sym);
3701
            setNodeSymbol(self, node, sym);
3702
            match sym.data {
3703
                case SymbolData::Value { type, .. } =>
3704
                    return setNodeType(self, node, type),
3705
                case SymbolData::Constant { type, value } => {
3706
                    if let val = value {
3707
                        setNodeConstValue(self, node, val);
3708
                    }
3709
                    return setNodeType(self, node, type);
3710
                },
3711
                case SymbolData::Type(t) =>
3712
                    return setNodeType(self, node, Type::Nominal(hintedNominal(t, hint))),
3713
                case SymbolData::Variant { .. } =>
3714
                    return Type::Void,
3715
                case SymbolData::Module { .. } =>
3716
                    throw emitError(self, node, ErrorKind::UnexpectedModuleName),
3717
                case SymbolData::Trait(_) =>
3718
                    throw emitError(self, node, ErrorKind::UnexpectedTraitName),
3719
            }
3720
        },
3721
        case ast::NodeValue::Call(call) => return try resolveCall(self, node, call, CallCtx::Normal, hint),
3722
        case ast::NodeValue::FieldAccess(access) => return try resolveFieldAccess(self, node, access),
3723
        case ast::NodeValue::BinOp(binop) => return try resolveBinOp(self, node, binop),
3724
        case ast::NodeValue::RegionBlock { region, bindings, body, isSession } => {
3725
            if isSession {
3726
                return try resolveSessionBlock(self, node, region, bindings, body);
3727
            }
3728
            return try resolveBorrowBlock(self, node, region, bindings, body);
3729
        }
3730
        case ast::NodeValue::Block(block) => return try resolveBlock(self, node, block),
3731
        case ast::NodeValue::Let(decl) => return try resolveLet(self, node, decl),
3732
        case ast::NodeValue::ConstDecl(decl) => return try resolveConstOrStatic(
3733
            self, node, decl.ident, decl.type, decl.value, decl.attrs, true
3734
        ),
3735
        case ast::NodeValue::StaticDecl(decl) => return try resolveConstOrStatic(
3736
            self, node, decl.ident, decl.type, decl.value, decl.attrs, false
3737
        ),
3738
        case ast::NodeValue::FnParam(param) => return try resolveFnParam(self, node, param),
3739
        case ast::NodeValue::If(cond) => return try resolveIf(self, node, cond),
3740
        case ast::NodeValue::CondExpr(cond) => return try resolveCondExpr(self, node, cond, hint),
3741
        case ast::NodeValue::IfLet(cond) => return try resolveIfLet(self, node, cond),
3742
        case ast::NodeValue::While(loopNode) => return try resolveWhile(self, node, loopNode),
3743
        case ast::NodeValue::WhileLet(loopNode) => return try resolveWhileLet(self, node, loopNode),
3744
        case ast::NodeValue::For(loopNode) => return try resolveFor(self, node, loopNode),
3745
        case ast::NodeValue::Loop { body } => {
3746
            let loopType = try visitLoop(self, body);
3747
            return setNodeType(self, node, loopType);
3748
        },
3749
        case ast::NodeValue::Break => {
3750
            try ensureInsideLoop(self, node);
3751
            // Mark that the current loop has a reachable break.
3752
            set self.loopStack[self.loopDepth - 1].hasBreak = true;
3753
3754
            return setNodeType(self, node, Type::Never);
3755
        },
3756
        case ast::NodeValue::Continue => {
3757
            try ensureInsideLoop(self, node);
3758
            return setNodeType(self, node, Type::Never);
3759
        },
3760
        case ast::NodeValue::Match(sw) => return try resolveMatch(self, node, sw),
3761
        case ast::NodeValue::MatchProng(_) => panic "visit: `MatchProng` not handled here",
3762
        case ast::NodeValue::LetElse(letElse) => return try resolveLetElse(self, node, letElse),
3763
        case ast::NodeValue::BuiltinCall { kind, args } => return try resolveBuiltinCall(self, node, kind, args),
3764
        case ast::NodeValue::Assign(assign) => return try resolveAssign(self, node, assign),
3765
        case ast::NodeValue::RecordLit(lit) => return try resolveRecordLit(self, node, lit, hint),
3766
        case ast::NodeValue::ArrayLit(items) => return try resolveArrayLit(self, node, items, hint),
3767
        case ast::NodeValue::ArrayRepeatLit(lit) => return try resolveArrayRepeat(self, node, lit, hint),
3768
        case ast::NodeValue::Subscript { container, index } => return try resolveSubscript(self, node, container, index),
3769
        case ast::NodeValue::ScopeAccess(access) => return try resolveScopeAccess(self, node, access, hint),
3770
        case ast::NodeValue::AddressOf(addr) => return try resolveAddressOf(self, node, addr, hint),
3771
        case ast::NodeValue::Deref(target) => return try resolveDeref(self, node, target, hint),
3772
        case ast::NodeValue::As(expr) => return try resolveAs(self, node, expr),
3773
        case ast::NodeValue::Range(range) => return try resolveRange(self, node, range),
3774
        case ast::NodeValue::Try(expr) => return try resolveTry(self, node, expr, hint),
3775
        case ast::NodeValue::Return { value } => return try resolveReturn(self, node, value),
3776
        case ast::NodeValue::Throw { expr } => return try resolveThrow(self, node, expr),
3777
        case ast::NodeValue::Panic { message } => {
3778
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
3779
                class: types::PointerClass::Owned,
3780
                item: allocType(self, Type::U8),
3781
                mutable: false,
3782
            });
3783
            return setNodeType(self, node, Type::Never);
3784
        },
3785
        case ast::NodeValue::Assert { condition, message } => {
3786
            try visit(self, condition, Type::Bool);
3787
            try visitOptional(self, message, Type::Slice { // TODO: Have easy access to string type.
3788
                class: types::PointerClass::Owned,
3789
                item: allocType(self, Type::U8),
3790
                mutable: false,
3791
            });
3792
            return setNodeType(self, node, Type::Void);
3793
        },
3794
        case ast::NodeValue::UnOp(unop) => return try resolveUnOp(self, node, unop),
3795
        case ast::NodeValue::ExprStmt(expr) => {
3796
            // Pass `Void` as expected type to indicate value is discarded.
3797
            let exprTy = try visit(self, expr, Type::Void);
3798
            return setNodeType(self, node, Type::Never if exprTy == Type::Never else Type::Void);
3799
        },
3800
        case ast::NodeValue::RegionApply { value, regions } =>
3801
            return try resolveRegionApply(self, node, value, regions),
3802
        case ast::NodeValue::TypeSig(sig) => return try inferTypeSig(self, node, sig),
3803
        case ast::NodeValue::Super => {
3804
            // `super` by itself is invalid, must be used in scope access.
3805
            throw emitError(self, node, ErrorKind::InvalidModulePath);
3806
        },
3807
        case ast::NodeValue::Nil => {
3808
            // Use the hint type if it's an optional, otherwise fall back to `Nil`.
3809
            if let case Type::Optional(_) = hint {
3810
                return setNodeType(self, node, hint);
3811
            }
3812
            return setNodeType(self, node, Type::Nil);
3813
        },
3814
        case ast::NodeValue::Undef => {
3815
            try requireUnsafe(self, node);
3816
            return setNodeType(self, node, Type::Undefined);
3817
        },
3818
        case ast::NodeValue::Bool(value) => {
3819
            setNodeConstValue(self, node, ConstValue::Bool(value));
3820
            return setNodeType(self, node, Type::Bool);
3821
        }
3822
        case ast::NodeValue::Char(value) => {
3823
            setNodeConstValue(self, node, ConstValue::Char(value));
3824
            return setNodeType(self, node, Type::U8);
3825
        }
3826
        case ast::NodeValue::String(text) => {
3827
            setNodeConstValue(self, node, ConstValue::String(text));
3828
            let byteTy = allocType(self, Type::U8);
3829
            let sliceTy = allocType(self, Type::Slice {
3830
                class: types::PointerClass::Owned,
3831
                item: byteTy,
3832
                mutable: false,
3833
            });
3834
            return setNodeType(self, node, *sliceTy);
3835
        },
3836
        case ast::NodeValue::Number(lit) => {
3837
            setNodeConstValue(self, node, ConstValue::Int(ConstInt {
3838
                magnitude: lit.magnitude,
3839
                bits: 64,
3840
                signed: false,
3841
                negative: false,
3842
            }));
3843
            return setNodeType(self, node, Type::Int);
3844
        },
3845
        case ast::NodeValue::Placeholder => {
3846
            return setNodeType(self, node, hint);
3847
        },
3848
        else => {
3849
            throw emitError(self, node, ErrorKind::UnexpectedNode(node));
3850
        }
3851
    }
3852
}
3853
3854
/// Visit an optional node when present.
3855
unsafe fn visitOptional 'arena (self: &mut Resolver 'arena, node: ?*ast::Node, hint: Type) -> ?Type
3856
    throws (ResolveError)
3857
{
3858
    if let n = node {
3859
        return try visit(self, n, hint);
3860
    }
3861
    return nil;
3862
}
3863
3864
/// Visit every node contained in a list, returning the last resolved type.
3865
unsafe fn visitList 'arena (self: &mut Resolver 'arena, list: *[*ast::Node]) -> Type
3866
    throws (ResolveError)
3867
{
3868
    let mut diverges = false;
3869
    for item in list {
3870
        if try infer(self, item) == Type::Never {
3871
            set diverges = true;
3872
        }
3873
    }
3874
    if diverges {
3875
        return Type::Never;
3876
    }
3877
    return Type::Void;
3878
}
3879
3880
/// Collect attribute flags applied to a declaration.
3881
fn resolveAttributes(attrs: ?ast::Attributes) -> u32 {
3882
    let list = attrs else return 0;
3883
    let mut mask: u32 = 0;
3884
3885
    for node in list.list {
3886
        let case ast::NodeValue::Attribute(attr) = node.value
3887
            else panic "resolveAttributes: invalid attribute node";
3888
        set mask |= (attr as u32);
3889
    }
3890
    return mask;
3891
}
3892
3893
/// Ensure the `default` attribute is only applied to functions.
3894
unsafe fn ensureDefaultAttrNotAllowed 'arena (self: &mut Resolver 'arena, node: *ast::Node, attrs: u32)
3895
    throws (ResolveError)
3896
{
3897
    let defaultBit = ast::Attribute::Default as u32;
3898
    if (attrs & defaultBit) <> 0 {
3899
        throw emitError(self, node, ErrorKind::DefaultAttrOnlyOnFn);
3900
    }
3901
}
3902
3903
/// Analyze a block node, allocating a nested lexical scope.
3904
unsafe fn resolveBlock 'arena (self: &mut Resolver 'arena, node: *ast::Node, block: ast::Block) -> Type
3905
    throws (ResolveError)
3906
{
3907
    enterScope(self, node);
3908
    let wasUnsafe = self.inUnsafeContext;
3909
    set self.inUnsafeContext = wasUnsafe or block.isUnsafe;
3910
    let blockTy = try visitList(self, block.statements) catch {
3911
        // One of the statements in the block failed analysis. We simply proceed
3912
        // without checking the rest of the block statements. Return `Never` to
3913
        // avoid spurious `FnMissingReturn` errors.
3914
        exitScope(self);
3915
        set self.inUnsafeContext = wasUnsafe;
3916
        return setNodeType(self, node, Type::Never);
3917
    };
3918
    exitScope(self);
3919
    set self.inUnsafeContext = wasUnsafe;
3920
3921
    return setNodeType(self, node, blockTy);
3922
}
3923
3924
/// Introduce a concrete region under an explicit parent or enclosing region block.
3925
unsafe fn borrowRegion 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> *RegionScope throws (ResolveError) {
3926
    let case ast::NodeValue::Region { name, parent } = node.value
3927
        else panic "borrowRegion: invalid region node";
3928
    if findRegion(self.regionScope, name) <> nil {
3929
        throw emitError(self, node, ErrorKind::DuplicateBinding(name));
3930
    }
3931
    let mut enclosing: ?*unsafe types::Region = nil;
3932
    let mut current = self.regionScope;
3933
    while let scope = current {
3934
        for region in scope.entries {
3935
            if region.origin == types::RegionOrigin::Block {
3936
                set enclosing = region;
3937
                break;
3938
            }
3939
        }
3940
        if enclosing <> nil {
3941
            break;
3942
        }
3943
        set current = scope.parent;
3944
    }
3945
    if let parentNode = parent {
3946
        set enclosing = try resolveRegion(self, parentNode);
3947
    }
3948
    let region = try! alloc::allocRaw(self.arena, @sizeOf(types::Region), @alignOf(types::Region))
3949
        as *unsafe mut types::Region;
3950
    set *region = types::Region { id: node.id, origin: types::RegionOrigin::Block, name, parent: enclosing };
3951
    let entries = try! alloc::allocRawSlice(
3952
        self.arena, @sizeOf(*unsafe mut types::Region), @alignOf(*unsafe mut types::Region), 1
3953
    ) as *unsafe mut [*unsafe mut types::Region];
3954
    set entries[0] = region;
3955
    let scope = try! alloc::alloc(&mut *self.arena, @sizeOf(RegionScope), @alignOf(RegionScope)) as *mut RegionScope;
3956
    set *scope = RegionScope { entries, parent: self.regionScope };
3957
    return scope;
3958
}
3959
3960
/// Qualify an existing-place borrow with its block's region.
3961
unsafe fn qualifyBlockBorrow 'arena (
3962
    self: &mut Resolver 'arena, node: *ast::Node, ty: Type, region: *unsafe types::Region
3963
) -> Type throws (ResolveError) {
3964
    let mut class = types::PointerClass::Ref;
3965
    match ty {
3966
        case Type::Cell { class: cellClass, .. } => set class = cellClass,
3967
        case Type::Pointer { class: pointerClass, .. } => set class = pointerClass,
3968
        case Type::Slice { class: sliceClass, .. } => set class = sliceClass,
3969
        else => throw emitError(self, node, ErrorKind::RefBinding),
3970
    }
3971
    if let case types::PointerClass::Region(source) = class {
3972
        if not types::regionContains(source, region) {
3973
            throw emitError(self, node, ErrorKind::RegionParent(region.name));
3974
        }
3975
    }
3976
    match ty {
3977
        case Type::Cell { payload, .. } =>
3978
            return Type::Cell { class: types::PointerClass::Region(region), payload },
3979
        case Type::Pointer { target, mutable, .. } =>
3980
            return Type::Pointer { class: types::PointerClass::Region(region), target, mutable },
3981
        case Type::Slice { item, mutable, .. } =>
3982
            return Type::Slice { class: types::PointerClass::Region(region), item, mutable },
3983
        else => throw emitError(self, node, ErrorKind::RefBinding),
3984
    }
3985
}
3986
3987
/// Check source places before publishing the region's bindings to its body.
3988
unsafe fn resolveBorrowBlock 'arena (
3989
    self: &mut Resolver 'arena, node: *ast::Node, regionNode: *ast::Node,
3990
    bindings: *[*ast::Node], body: *ast::Node
3991
) -> Type throws (ResolveError) {
3992
    if self.currentFn == nil {
3993
        throw emitError(self, node, ErrorKind::InvalidRefPosition);
3994
    }
3995
    let scope = try borrowRegion(self, regionNode);
3996
    let region = scope.entries[0];
3997
    for bindingNode in bindings {
3998
        let case ast::NodeValue::RegionBinding(binding) = bindingNode.value
3999
            else panic "resolveBorrowBlock: invalid binding node";
4000
        let case ast::NodeValue::AddressOf(address) = binding.value.value
4001
            else panic "resolveBorrowBlock: invalid source node";
4002
        let ty = try infer(self, binding.value);
4003
        if not ast::isPlaceExpr(address.target) or borrowPlace(self, address.target).root == nil {
4004
            throw emitError(self, binding.value, ErrorKind::RefBinding);
4005
        }
4006
        let qualified = try qualifyBlockBorrow(self, binding.value, ty, region);
4007
        setNodeType(self, binding.value, qualified);
4008
    }
4009
    let previous = self.regionScope;
4010
    set self.regionScope = scope;
4011
    set self.nodeData.entries[node.id].extra = NodeExtra::Regions(scope);
4012
    enterScope(self, node);
4013
    let result = try resolveBorrowBody(self, bindings, body) catch error {
4014
        exitScope(self);
4015
        set self.regionScope = previous;
4016
        throw error;
4017
    };
4018
    exitScope(self);
4019
    set self.regionScope = previous;
4020
    return setNodeType(self, node, result);
4021
}
4022
4023
/// Bind a checked region's source references and resolve its statement body.
4024
unsafe fn resolveBorrowBody 'arena (self: &mut Resolver 'arena, bindings: *[*ast::Node], body: *ast::Node) -> Type
4025
    throws (ResolveError)
4026
{
4027
    for bindingNode in bindings {
4028
        let case ast::NodeValue::RegionBinding(binding) = bindingNode.value
4029
            else panic "resolveBorrowBody: invalid binding node";
4030
        try resolveLet(self, bindingNode, ast::borrowBinding(binding));
4031
    }
4032
    return try infer(self, body);
4033
}
4034
4035
/// Find a declaration by spelling when the name is not interned.
4036
unsafe fn findSpelledSymbol(scope: *unsafe Scope, name: *[u8]) -> ?*unsafe mut Symbol {
4037
    for i in 0..scope.symbolsLen {
4038
        let symbol = scope.symbols[i];
4039
        if mem::eq(symbol.name, name) {
4040
            return symbol;
4041
        }
4042
    }
4043
    return nil;
4044
}
4045
4046
/// Look up a compiler-known declaration in the standard allocation module.
4047
unsafe fn allocationSymbol 'arena (self: &Resolver 'arena, name: *[u8]) -> ?*unsafe mut Symbol {
4048
    let mut scope = self.pkgScope;
4049
    for segment in ["std", "lang", "alloc"] {
4050
        let symbol = findSpelledSymbol(scope, segment) else return nil;
4051
        let case SymbolData::Module { scope: child, .. } = symbol.data else return nil;
4052
        set scope = child;
4053
    }
4054
    return findSpelledSymbol(scope, name);
4055
}
4056
4057
/// Bind an allocation interface while retaining the source arena until region exit.
4058
unsafe fn resolveSessionBlock 'arena (
4059
    self: &mut Resolver 'arena, node: *ast::Node, regionNode: *ast::Node,
4060
    bindings: *[*ast::Node], body: *ast::Node
4061
) -> Type throws (ResolveError) {
4062
    if self.currentFn == nil or bindings.len <> 1 {
4063
        throw emitError(self, node, ErrorKind::InvalidSessionSource);
4064
    }
4065
    let bindingNode = bindings[0];
4066
    let case ast::NodeValue::RegionBinding(binding) = bindingNode.value
4067
        else panic "resolveSessionBlock: invalid binding";
4068
    let case ast::NodeValue::AddressOf(address) = binding.value.value
4069
        else throw emitError(self, binding.value, ErrorKind::InvalidSessionSource);
4070
    let ty = try infer(self, binding.value);
4071
    let case Type::Pointer { target, .. } = ty
4072
        else throw emitError(self, binding.value, ErrorKind::InvalidSessionSource);
4073
    let allocTrait = allocationSymbol(self, "Alloc")
4074
        else throw emitError(self, node, ErrorKind::InvalidSessionSource);
4075
    let case SymbolData::Trait(allocInfo) = allocTrait.data
4076
        else throw emitError(self, node, ErrorKind::InvalidSessionSource);
4077
    let allocModule = moduleIdForSymbol(self, allocTrait)
4078
        else throw emitError(self, node, ErrorKind::InvalidSessionSource);
4079
    let mut allocInstance: ?*unsafe InstanceEntry = nil;
4080
    for i in 0..self.instancesLen {
4081
        let candidate: *unsafe InstanceEntry = &self.instances[i];
4082
        if candidate.traitType.moduleId == allocModule and mem::eq(candidate.traitType.name, allocInfo.name)
4083
            and erasedTypesEqual(candidate.concreteType, *target)
4084
        {
4085
            set allocInstance = candidate;
4086
            break;
4087
        }
4088
    }
4089
    let selected = allocInstance
4090
        else throw emitError(self, node, ErrorKind::InvalidSessionSource);
4091
    if address.kind <> ast::AddressKind::Mutable or not ast::isPlaceExpr(address.target)
4092
        or borrowPlace(self, address.target).root == nil
4093
    {
4094
        throw emitError(self, binding.value, ErrorKind::InvalidSessionSource);
4095
    }
4096
    let _ = setNodeCoercion(self, binding.value, Coercion::TraitObject {
4097
        traitInfo: allocInfo, inst: selected,
4098
    });
4099
    let scope = try borrowRegion(self, regionNode);
4100
    let region = scope.entries[0];
4101
    if let sourceRegion = referenceRegion(ty) {
4102
        set region.parent = sourceRegion;
4103
    }
4104
    setNodeType(self, binding.value, try qualifyBlockBorrow(self, binding.value, ty, region));
4105
    let previous = self.regionScope;
4106
    set self.regionScope = scope;
4107
    set self.nodeData.entries[node.id].extra = NodeExtra::Regions(scope);
4108
    enterScope(self, node);
4109
    let result = try resolveSessionBody(self, bindingNode, binding, region, body) catch error {
4110
        exitScope(self);
4111
        set self.regionScope = previous;
4112
        throw error;
4113
    };
4114
    exitScope(self);
4115
    set self.regionScope = previous;
4116
    return setNodeType(self, node, result);
4117
}
4118
4119
/// Introduce the opaque session value and check its body.
4120
unsafe fn resolveSessionBody 'arena (
4121
    self: &mut Resolver 'arena, node: *ast::Node, binding: ast::Arg,
4122
    region: *unsafe types::Region, body: *ast::Node
4123
) -> Type throws (ResolveError) {
4124
    let ident = binding.label else panic "resolveSessionBody: missing binding name";
4125
    let _ = try bindValueIdent(self, ident, node, Type::Session(region), false, 0, 0);
4126
    return try infer(self, body);
4127
}
4128
4129
/// Analyze a `let` declaration and bind its identifier.
4130
unsafe fn resolveLet 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::Let) -> Type
4131
    throws (ResolveError)
4132
{
4133
    let mut alignment: u32 = 0; // Zero is default.
4134
    let mut bindingTy = Type::Unknown;
4135
    let mut valueTy = Type::Unknown;
4136
4137
    // Check type.
4138
    if let declTy = try visitOptional(self, decl.type, Type::Unknown) {
4139
        set valueTy = try checkAssignable(self, decl.value, declTy);
4140
        set bindingTy = declTy;
4141
    } else {
4142
        set bindingTy = try infer(self, decl.value);
4143
        set valueTy = bindingTy;
4144
4145
        if not isTypeInferrable(bindingTy) {
4146
            throw emitError(self, decl.value, ErrorKind::CannotInferType);
4147
        }
4148
    }
4149
    try validateValueTypeReferences(self, node, bindingTy);
4150
    if isRefType(bindingTy) {
4151
        if self.currentFn == nil {
4152
            throw emitError(self, node, ErrorKind::InvalidRefPosition);
4153
        }
4154
        if decl.mutable and (referenceRegion(bindingTy) == nil or not isCopy(bindingTy)) {
4155
            throw emitError(self, node, ErrorKind::RefBinding);
4156
        }
4157
    }
4158
    // Variables cannot have void type.
4159
    if bindingTy == Type::Void {
4160
        throw emitError(self, decl.value, ErrorKind::CannotAssignVoid);
4161
    }
4162
    // Variables cannot have opaque type directly.
4163
    if bindingTy == Type::Opaque {
4164
        throw emitError(self, node, ErrorKind::OpaqueTypeNotAllowed);
4165
    }
4166
    // Check alignment.
4167
    if let a = decl.alignment {
4168
        let case ast::NodeValue::Align { value } = a.value
4169
            else panic "resolveLet: expected Align node";
4170
        set alignment = try checkSizeInt(self, value);
4171
    }
4172
    assert bindingTy <> Type::Unknown;
4173
4174
    // Alignment must be zero or a power of two.
4175
    if alignment <> 0 and (alignment & (alignment - 1)) <> 0 {
4176
        throw emitError(self, decl.value, ErrorKind::InvalidAlignmentValue(alignment));
4177
    }
4178
    let _ = try bindValueIdent(self, decl.ident, node, bindingTy, decl.mutable, alignment, 0);
4179
4180
    // Untyped initializers use the declared storage type.
4181
    if not isTypeInferrable(valueTy) {
4182
        setNodeType(self, decl.value, bindingTy);
4183
    }
4184
4185
    return Type::Never if valueTy == Type::Never else Type::Void;
4186
}
4187
4188
/// Check whether a node is an integer literal, optionally under unary negation.
4189
fn isIntegerLiteralExpr(node: *ast::Node) -> bool {
4190
    match node.value {
4191
        case ast::NodeValue::Number(_) => return true,
4192
        case ast::NodeValue::UnOp(unop) => {
4193
            if unop.op == ast::UnaryOp::Neg {
4194
                return isIntegerLiteralExpr(unop.value);
4195
            }
4196
            return false;
4197
        },
4198
        else => return false,
4199
    }
4200
}
4201
4202
/// Determine whether a node represents a compile-time constant expression.
4203
export unsafe fn isConstExpr 'arena (self: &Resolver 'arena, node: *ast::Node) -> bool {
4204
    match node.value {
4205
        case ast::NodeValue::Bool(_),
4206
             ast::NodeValue::Char(_),
4207
             ast::NodeValue::Number(_),
4208
             ast::NodeValue::String(_),
4209
             ast::NodeValue::Undef,
4210
             ast::NodeValue::Nil => {
4211
            return true;
4212
        },
4213
        case ast::NodeValue::ArrayLit(items) => {
4214
            for item in items {
4215
                if not isConstExpr(self, item) {
4216
                    return false;
4217
                }
4218
            }
4219
            return true;
4220
        },
4221
        case ast::NodeValue::ArrayRepeatLit(repeat) => {
4222
            return isConstExpr(self, repeat.item);
4223
        },
4224
        case ast::NodeValue::AddressOf(addr) => {
4225
            let ty = typeFor(self, node) else {
4226
                return false;
4227
            };
4228
            if let case Type::Slice { .. } = ty {
4229
                return isConstExpr(self, addr.target);
4230
            }
4231
            return false;
4232
        },
4233
        case ast::NodeValue::RecordLit(lit) => {
4234
            // Record literals are constant if all field values are constant.
4235
            for field in lit.fields {
4236
                if let case ast::NodeValue::RecordLitField(fieldLit) = field.value {
4237
                    if not isConstExpr(self, fieldLit.value) {
4238
                        return false;
4239
                    }
4240
                }
4241
            }
4242
            return true;
4243
        },
4244
        case ast::NodeValue::Ident(_),
4245
             ast::NodeValue::ScopeAccess(_) => {
4246
            // Identifiers and scope accesses referencing constants, union
4247
            // variants, or function values are constant expressions.
4248
            if let sym = symbolFor(self, node) {
4249
                match sym.data {
4250
                    case SymbolData::Variant { .. },
4251
                         SymbolData::Constant { .. } => return true,
4252
                    case SymbolData::Value { type, .. } => {
4253
                        if let case Type::Fn(_) = type {
4254
                            return true;
4255
                        }
4256
                    }
4257
                    else => {}
4258
                }
4259
            }
4260
            return false;
4261
        },
4262
        case ast::NodeValue::Call(call) => {
4263
            // Constructor calls (union variants, unlabeled records) are constant
4264
            // if all payload args are themselves constant.
4265
            if let sym = symbolFor(self, call.callee) {
4266
                match sym.data {
4267
                    case SymbolData::Variant { .. } => {}
4268
                    case SymbolData::Type(NominalType::Record(recInfo)) => {
4269
                        if recInfo.labeled {
4270
                            return false;
4271
                        }
4272
                    },
4273
                    else => return false,
4274
                }
4275
                for arg in call.args {
4276
                    if not isConstExpr(self, arg) {
4277
                        return false;
4278
                    }
4279
                }
4280
                return true;
4281
            }
4282
            return false;
4283
        },
4284
        case ast::NodeValue::BinOp(binop) => {
4285
            // Binary expressions are constant if both operands are constant.
4286
            return isConstExpr(self, binop.left) and isConstExpr(self, binop.right);
4287
        },
4288
        case ast::NodeValue::UnOp(unop) => {
4289
            // Unary expressions are constant if the operand is constant.
4290
            return isConstExpr(self, unop.value);
4291
        },
4292
        case ast::NodeValue::As(expr) => {
4293
            // Cast expressions are constant if the source value is constant.
4294
            return isConstExpr(self, expr.value);
4295
        },
4296
        else => {
4297
            return false;
4298
        }
4299
    }
4300
}
4301
4302
/// Construct an integer constant descriptor.
4303
fn constInt(magnitude: u64, bits: u8, signed: bool, negative: bool) -> ConstValue {
4304
    return ConstValue::Int(ConstInt { magnitude, bits, signed, negative });
4305
}
4306
4307
/// Apply an integer cast to a constant value, including target-width
4308
/// truncation and signed interpretation.
4309
fn castConstInt(value: ConstInt, target: Type) -> ConstValue {
4310
    let raw = constIntToBits(value);
4311
    let range = integerRange(target)
4312
        else panic "castConstInt: expected integer type";
4313
4314
    match range {
4315
        case IntegerRange::Unsigned { bits, .. } =>
4316
            return ConstValue::Int(constIntFromBits(raw, bits, false)),
4317
        case IntegerRange::Signed { bits, .. } =>
4318
            return ConstValue::Int(constIntFromBits(raw, bits, true)),
4319
    }
4320
}
4321
4322
/// Return the constant `u32` value for a slice bound when known.
4323
fn constSliceIndex 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> ?u32 {
4324
    let value = constValueEntry(self, node)
4325
        else return nil;
4326
    let case ConstValue::Int(int) = value
4327
        else return nil;
4328
    if int.negative {
4329
        return nil;
4330
    }
4331
    return int.magnitude as u32;
4332
}
4333
4334
/// Validates and extracts a non-negative integer constant from a compile-time expression.
4335
///
4336
/// This function ensures that a node represents a valid, non-negative integer constant
4337
/// that fits within a machine word. It is used for contexts requiring compile-time
4338
/// non-negative integers, such as array sizes and alignment specifications.
4339
///
4340
/// Returns the unsigned magnitude of the constant as `u32`.
4341
unsafe fn checkSizeInt 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> u32
4342
    throws (ResolveError)
4343
{
4344
    // First traverse the node expect a numeric type.
4345
    let _ = try checkNumeric(self, node);
4346
4347
    // Look up the compile-time constant value associated with this node.
4348
    let value = constValueEntry(self, node)
4349
        else throw emitError(self, node, ErrorKind::ConstExprRequired);
4350
4351
    let case ConstValue::Int(int) = value
4352
        else panic "checkSizeInt: expected integer constant";
4353
4354
    // Validate it fits within u32 range.
4355
    if not validateConstIntRange(value, Type::U32) {
4356
        throw emitError(self, node, ErrorKind::NumericLiteralOverflow);
4357
    }
4358
    assert not int.negative;
4359
    setNodeType(self, node, Type::U32);
4360
4361
    return int.magnitude as u32;
4362
}
4363
4364
/// Check that constructor arguments match record fields.
4365
///
4366
/// Verifies argument count matches field count, and that each argument is
4367
/// assignable to its corresponding field type.
4368
unsafe fn checkRecordConstructorArgs 'arena (self: &mut Resolver 'arena, node: *ast::Node, args: *[*ast::Node], recInfo: RecordType)
4369
    throws (ResolveError)
4370
{
4371
    try checkRecordArity(self, args, recInfo, node);
4372
    for arg, i in args {
4373
        let fieldType = recInfo.fields[i].fieldType;
4374
        try checkAssignable(self, arg, fieldType);
4375
    }
4376
}
4377
4378
/// Check that the argument count of a constructor pattern or call matches the record field count.
4379
unsafe fn checkRecordArity 'arena (self: &mut Resolver 'arena, args: *[*ast::Node], recInfo: RecordType, pattern: *ast::Node) throws (ResolveError) {
4380
    if args.len <> recInfo.fields.len {
4381
        throw emitError(self, pattern, ErrorKind::RecordFieldCountMismatch(CountMismatch {
4382
            expected: recInfo.fields.len as u32,
4383
            actual: args.len,
4384
        }));
4385
    }
4386
}
4387
4388
/// Helper for analyzing `constant` and `static` declarations.
4389
unsafe fn resolveConstOrStatic 'arena (
4390
    self: &mut Resolver 'arena,
4391
    node: *ast::Node,
4392
    ident: *ast::Node,
4393
    typeNode: *ast::Node,
4394
    valueNode: *ast::Node,
4395
    attrList: ?ast::Attributes,
4396
    isConst: bool
4397
) -> Type throws (ResolveError) {
4398
    let attrs = resolveAttributes(attrList);
4399
    let bindingTy = try infer(self, typeNode);
4400
    if containsRegion(bindingTy) {
4401
        throw emitError(self, typeNode, ErrorKind::InvalidRefPosition);
4402
    }
4403
    try ensureStorableType(self, typeNode, bindingTy);
4404
    let wasUnsafe = self.inUnsafeContext;
4405
    set self.inUnsafeContext = wasUnsafe or (
4406
        not isConst and ast::hasAttribute(attrs, ast::Attribute::Unsafe)
4407
    );
4408
    let valueTy = try checkAssignable(self, valueNode, bindingTy) catch e {
4409
        set self.inUnsafeContext = wasUnsafe;
4410
        throw e;
4411
    };
4412
    set self.inUnsafeContext = wasUnsafe;
4413
4414
    if isConst {
4415
        let mut constVal = constValueEntry(self, valueNode);
4416
        if constVal == nil and not isConstExpr(self, valueNode) {
4417
            throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
4418
        }
4419
        if let val = constVal {
4420
            if let case ConstValue::Int(int) = val; isNumericType(bindingTy) {
4421
                set constVal = castConstInt(int, bindingTy);
4422
            }
4423
        }
4424
        try bindConstIdent(self, ident, node, bindingTy, constVal, attrs);
4425
    } else {
4426
        if not isConstExpr(self, valueNode) {
4427
            throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
4428
        }
4429
        try bindValueIdent(self, ident, node, bindingTy, true, 0, attrs);
4430
    }
4431
    setNodeType(self, valueNode, bindingTy);
4432
4433
    return Type::Void;
4434
}
4435
4436
/// Analyze a function declaration signature and bind the function name.
4437
unsafe fn resolveFnDecl 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::FnDecl) -> Type
4438
    throws (ResolveError)
4439
{
4440
    let previous = self.regionScope;
4441
    set self.regionScope = try bindRegions(self, node, decl.regions);
4442
    let result = try resolveFnSignature(self, node, decl) catch error {
4443
        set self.regionScope = previous;
4444
        throw error;
4445
    };
4446
    set self.regionScope = previous;
4447
    return result;
4448
}
4449
4450
/// Resolve a function signature in its declared region environment.
4451
unsafe fn resolveFnSignature 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::FnDecl) -> Type
4452
    throws (ResolveError)
4453
{
4454
    let attrMask = resolveAttributes(decl.attrs);
4455
    let mut retTy = Type::Void;
4456
    if let retNode = decl.sig.returnType {
4457
        set retTy = try infer(self, retNode);
4458
        try ensureStorableType(self, retNode, retTy);
4459
    }
4460
    let a = alloc::arenaAllocator(self.arena);
4461
    let mut paramTypes: *mut [*Type] = &mut [];
4462
    let mut throwList: *mut [*Type] = &mut [];
4463
    let mut fnType = FnType {
4464
        regions: self.regionScope,
4465
        paramTypes: &[],
4466
        returnType: allocType(self, retTy),
4467
        throwList: &[],
4468
        isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe),
4469
    };
4470
    // Enter the function scope to process parameters.
4471
    enterFn(self, node, &fnType);
4472
4473
    if decl.sig.params.len > MAX_FN_PARAMS {
4474
        exitFn(self);
4475
        throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
4476
            expected: MAX_FN_PARAMS,
4477
            actual: decl.sig.params.len,
4478
        }));
4479
    }
4480
    for paramNode in decl.sig.params {
4481
        let paramTy = try infer(self, paramNode) catch e {
4482
            exitFn(self);
4483
            throw e;
4484
        };
4485
        paramTypes.append(allocType(self, paramTy), a);
4486
    }
4487
4488
    if decl.sig.throwList.len > MAX_FN_THROWS {
4489
        exitFn(self);
4490
        throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch {
4491
            expected: MAX_FN_THROWS,
4492
            actual: decl.sig.throwList.len,
4493
        }));
4494
    }
4495
    for throwNode in decl.sig.throwList {
4496
        let throwTy = try infer(self, throwNode) catch e {
4497
            exitFn(self);
4498
            throw e;
4499
        };
4500
        try validateErrorTag(self, throwNode, throwTy, &throwList[..]);
4501
        throwList.append(allocType(self, throwTy), a);
4502
        try ensureStorableType(self, throwNode, throwTy);
4503
    }
4504
    exitFn(self);
4505
    set fnType.paramTypes = &paramTypes[..];
4506
    set fnType.throwList = &throwList[..];
4507
4508
    // Bind the function name.
4509
    let ty = Type::Fn(allocFnType(self, fnType));
4510
    let sym = try bindValueIdent(self, decl.name, node, ty, false, 0, attrMask)
4511
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
4512
4513
    return ty;
4514
}
4515
4516
/// Analyze a function body.
4517
unsafe fn resolveFnDeclBody 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::FnDecl) throws (ResolveError) {
4518
    let sym = symbolFor(self, node) else {
4519
        // The function declaration failed to type check, therefore
4520
        // no symbol was associated with it.
4521
        return;
4522
    };
4523
    let case SymbolData::Value { type: Type::Fn(fnType), .. } = sym.data else {
4524
        panic "resolveFnDeclBody: unexpected symbol data for function";
4525
    };
4526
    let isExtern = ast::hasAttribute(sym.attrs, ast::Attribute::Extern);
4527
    let isIntrinsic = ast::hasAttribute(sym.attrs, ast::Attribute::Intrinsic);
4528
4529
    if let body = decl.body {
4530
        if isIntrinsic {
4531
            throw emitError(self, node, ErrorKind::IntrinsicUnexpectedBody);
4532
        }
4533
        if isExtern {
4534
            throw emitError(self, node, ErrorKind::FnUnexpectedBody);
4535
        }
4536
        let previous = self.regionScope;
4537
        set self.regionScope = try bindRegions(self, node, decl.regions);
4538
        try resolveExecutableBody(self, node, fnType, nil, decl.sig.params, body) catch error {
4539
            set self.regionScope = previous;
4540
            throw error;
4541
        };
4542
        set self.regionScope = previous;
4543
    } else if not isExtern {
4544
        throw emitError(self, node, ErrorKind::FnMissingBody);
4545
    }
4546
}
4547
4548
/// Resolve a function or method body and restore the enclosing context.
4549
unsafe fn resolveExecutableBody 'arena (
4550
    self: &mut Resolver 'arena,
4551
    node: *ast::Node,
4552
    fnType: *FnType,
4553
    receiverName: ?*ast::Node,
4554
    params: *[*ast::Node],
4555
    body: *ast::Node,
4556
) throws (ResolveError) {
4557
    let wasUnsafe = self.inUnsafeContext;
4558
    set self.inUnsafeContext = fnType.isUnsafe;
4559
    // Enter function scope.
4560
    enterFn(self, node, fnType); // Enter function scope for body analysis.
4561
4562
    let missingReturn = try checkExecutableBody(self, fnType, receiverName, params, body) catch e {
4563
        exitFn(self);
4564
        set self.inUnsafeContext = wasUnsafe;
4565
        throw e;
4566
    };
4567
    exitFn(self);
4568
    set self.inUnsafeContext = wasUnsafe;
4569
    if missingReturn {
4570
        throw emitError(self, body, ErrorKind::FnMissingReturn);
4571
    }
4572
}
4573
4574
/// Check parameters, body types, and ownership.
4575
/// Return whether a required return is missing.
4576
unsafe fn checkExecutableBody 'arena (
4577
    self: &mut Resolver 'arena,
4578
    fnType: *FnType,
4579
    receiverName: ?*ast::Node,
4580
    params: *[*ast::Node],
4581
    body: *ast::Node,
4582
) -> bool throws (ResolveError) {
4583
    if let receiver = receiverName {
4584
        // Bind the receiver parameter.
4585
        let receiverTy = *fnType.paramTypes[0];
4586
        try bindValueIdent(self, receiver, receiver, receiverTy, false, 0, 0);
4587
        // Bind the remaining parameters from the signature.
4588
        for paramNode in params {
4589
            let paramTy = try infer(self, paramNode);
4590
        }
4591
    }
4592
    // Resolve the body.
4593
    let retTy = *fnType.returnType;
4594
    let bodyTy = try checkAssignable(self, body, Type::Void);
4595
    if retTy <> Type::Void and bodyTy <> Type::Never {
4596
        return true;
4597
    }
4598
    try checkLinearFn(self, receiverName, params, body);
4599
    return false;
4600
}
4601
4602
/// Analyze a function parameter and bind its identifier.
4603
unsafe fn resolveFnParam 'arena (self: &mut Resolver 'arena, node: *ast::Node, param: ast::FnParam) -> Type
4604
    throws (ResolveError)
4605
{
4606
    let ty = try resolveValueType(self, param.type);
4607
    let _ = try bindValueIdent(self, param.name, node, ty, false, 0, 0);
4608
4609
    return ty;
4610
}
4611
4612
/// Compiler-known ownership markers carried by a composite declaration.
4613
record OwnershipMarkers: Copy {
4614
    /// The declaration requires exact consumption.
4615
    linear: bool,
4616
    /// The declaration permits implicit copies.
4617
    copy: bool,
4618
}
4619
4620
/// Resolve compiler-known ownership markers from a derive list.
4621
unsafe fn resolveOwnershipMarkers 'arena (self: &mut Resolver 'arena, derives: *[*ast::Node]) -> OwnershipMarkers
4622
    throws (ResolveError)
4623
{
4624
    let mut result = OwnershipMarkers { linear: false, copy: false };
4625
    for derive in derives {
4626
        if let case ast::NodeValue::Region { .. } = derive.value {
4627
            continue;
4628
        }
4629
        let name = try nodeName(self, derive);
4630
        if mem::eq(name, "Once") {
4631
            if result.linear {
4632
                throw emitError(self, derive, ErrorKind::DuplicateBinding(name));
4633
            }
4634
            if result.copy {
4635
                throw emitError(self, derive, ErrorKind::ConflictingOwnershipMarkers);
4636
            }
4637
            set result.linear = true;
4638
        } else if mem::eq(name, "Copy") {
4639
            if result.copy {
4640
                throw emitError(self, derive, ErrorKind::DuplicateBinding(name));
4641
            }
4642
            if result.linear {
4643
                throw emitError(self, derive, ErrorKind::ConflictingOwnershipMarkers);
4644
            }
4645
            set result.copy = true;
4646
        } else {
4647
            // Resolve an ordinary trait derive.
4648
            try infer(self, derive);
4649
        }
4650
    }
4651
    return result;
4652
}
4653
4654
/// Resolve record fields from a node list.
4655
unsafe fn resolveRecordFields 'arena (self: &mut Resolver 'arena, node: *ast::Node, fields: *[*ast::Node], labeled: bool) -> RecordType
4656
    throws (ResolveError)
4657
{
4658
    let a = alloc::arenaAllocator(self.arena);
4659
    let mut result: *unsafe mut [RecordField] = &mut [];
4660
    let mut currentOffset: u32 = 0;
4661
    let mut maxAlignment: u32 = 1;
4662
4663
    if fields.len > parser::MAX_RECORD_FIELDS {
4664
        throw emitError(self, node, ErrorKind::Internal);
4665
    }
4666
    for field in fields {
4667
        let case ast::NodeValue::RecordField {
4668
            field: fieldNode,
4669
            type: typeNode,
4670
            value: valueNode
4671
        } = field.value else panic "resolveRecordFields: invalid record field";
4672
        let fieldTy = try resolveValueType(self, typeNode);
4673
        try ensureStorableType(self, typeNode, fieldTy);
4674
4675
        if let v = valueNode {
4676
            let _valTy = try checkAssignable(self, v, fieldTy);
4677
        }
4678
        // Get field name for labeled records.
4679
        let mut fieldName: ?*[u8] = nil;
4680
        if labeled {
4681
            let n = fieldNode
4682
                else panic "resolveRecordFields: labeled record field missing name";
4683
            set fieldName = try nodeName(self, n);
4684
        }
4685
        let fieldType = typeFor(self, typeNode)
4686
            else throw emitError(self, typeNode, ErrorKind::CannotInferType);
4687
4688
        // Ensure field type is fully resolved before computing layout.
4689
        try ensureTypeResolved(self, fieldType, typeNode);
4690
4691
        // Compute field offset by aligning to field's alignment.
4692
        let fieldLayout = getTypeLayout(fieldType);
4693
        set currentOffset = mem::alignUp(currentOffset, fieldLayout.alignment);
4694
4695
        result.append(RecordField { name: fieldName, fieldType, offset: currentOffset as i32 }, a);
4696
4697
        // Advance offset past this field.
4698
        set currentOffset += fieldLayout.size;
4699
4700
        // Track max alignment for record layout.
4701
        set maxAlignment = max(maxAlignment, fieldLayout.alignment);
4702
    }
4703
    // Compute cached layout.
4704
    let recordLayout = Layout {
4705
        size: mem::alignUp(currentOffset, maxAlignment),
4706
        alignment: maxAlignment
4707
    };
4708
    return RecordType {
4709
        regions: nil,
4710
        application: nil,
4711
        fields: &result[..],
4712
        labeled,
4713
        layout: allocLayout(self, recordLayout),
4714
        declaredLinear: false,
4715
        declaredCopy: false,
4716
    };
4717
}
4718
4719
/// Resolve record field types for a named record declaration.
4720
unsafe fn resolveRecordBody 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::RecordDecl)
4721
    throws (ResolveError)
4722
{
4723
    let previous = self.regionScope;
4724
    set self.regionScope = try bindRegions(self, node, decl.regions);
4725
    try resolveRecordContents(self, node, decl) catch error {
4726
        set self.regionScope = previous;
4727
        throw error;
4728
    };
4729
    set self.regionScope = previous;
4730
}
4731
4732
/// Resolve record contents in the declaration's region environment.
4733
unsafe fn resolveRecordContents 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::RecordDecl)
4734
    throws (ResolveError)
4735
{
4736
    // Get the type symbol that was bound to this declaration node.
4737
    // If there's no symbol, it's because an earlier phase failed.
4738
    let sym = symbolFor(self, node)
4739
        else return;
4740
    let case SymbolData::Type(nominalTy) = sym.data
4741
        else panic "resolveRecordBody: unexpected type symbol data";
4742
4743
    // Skip if already resolved.
4744
    if let case NominalType::Record(_) = *nominalTy {
4745
        return;
4746
    }
4747
    let markers = try resolveOwnershipMarkers(self, decl.derives);
4748
    set *nominalTy = NominalType::Resolving(node);
4749
    let mut recordType = try resolveRecordFields(self, node, decl.fields, decl.labeled) catch error {
4750
        set *nominalTy = NominalType::Placeholder(node);
4751
        throw error;
4752
    };
4753
    set recordType.regions = self.regionScope;
4754
    if markers.copy {
4755
        for field in recordType.fields {
4756
            if not isCopy(field.fieldType) {
4757
                throw emitError(self, node, ErrorKind::CopyContainsNonCopy);
4758
            }
4759
        }
4760
    }
4761
    set recordType.declaredLinear = markers.linear;
4762
    set recordType.declaredCopy = markers.copy;
4763
4764
    set *nominalTy = NominalType::Record(recordType);
4765
}
4766
4767
/// Bind a type name.
4768
unsafe fn bindTypeName 'arena (self: &mut Resolver 'arena, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *unsafe mut Symbol
4769
    throws (ResolveError)
4770
{
4771
    let attrMask = resolveAttributes(attrs);
4772
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
4773
4774
    // Create a placeholder nominal type that will be replaced in
4775
    // the next phase.
4776
    let nominalTy = allocNominalType(self, NominalType::Placeholder(node));
4777
4778
    return try bindTypeIdent(self, name, node, nominalTy, attrMask);
4779
}
4780
4781
/// Allocate a trait type descriptor and return a pointer to it.
4782
unsafe fn allocTraitType 'arena (self: &mut Resolver 'arena, name: *[u8]) -> *unsafe mut TraitType {
4783
    let p = try! alloc::allocRaw(self.arena, @sizeOf(TraitType), @alignOf(TraitType));
4784
    let entry = p as *unsafe mut TraitType;
4785
    set *entry = TraitType { name, moduleId: self.currentMod, methods: &mut [], supertraits: &mut [] };
4786
4787
    return entry;
4788
}
4789
4790
/// Bind a trait name in the current scope.
4791
unsafe fn bindTraitName 'arena (self: &mut Resolver 'arena, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *unsafe mut Symbol
4792
    throws (ResolveError)
4793
{
4794
    let attrMask = resolveAttributes(attrs);
4795
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
4796
4797
    let traitName = try nodeName(self, name);
4798
    let traitType = allocTraitType(self, traitName);
4799
    let data = SymbolData::Trait(traitType);
4800
    let scope = self.scope;
4801
    let sym = try bindIdent(self, traitName, node, data, attrMask, scope);
4802
4803
    setNodeType(self, node, Type::Void);
4804
    setNodeType(self, name, Type::Void);
4805
4806
    return sym;
4807
}
4808
4809
/// Find a trait method by name.
4810
export unsafe fn findTraitMethod(traitType: *unsafe TraitType, name: *[u8]) -> ?*unsafe TraitMethod {
4811
    for i in 0..traitType.methods.len {
4812
        if mem::eq(traitType.methods[i].name, name) {
4813
            return &traitType.methods[i];
4814
        }
4815
    }
4816
    return nil;
4817
}
4818
4819
/// Resolve a trait declaration body: supertrait methods, then own methods.
4820
unsafe fn resolveTraitBody 'arena (self: &mut Resolver 'arena, node: *ast::Node, supertraits: *[*ast::Node], methods: *[*ast::Node])
4821
    throws (ResolveError)
4822
{
4823
    let sym = symbolFor(self, node)
4824
        else return;
4825
    let case SymbolData::Trait(traitType) = sym.data
4826
        else return;
4827
    if traitType.methods.len > 0 {
4828
        return;
4829
    }
4830
4831
    // Resolve supertrait bounds and copy their methods into this trait.
4832
    for superNode in supertraits {
4833
        let superSym = try resolveNamePath(self, superNode);
4834
        let case SymbolData::Trait(superTrait) = superSym.data
4835
            else throw emitError(self, superNode, ErrorKind::Internal);
4836
        // Trait bodies are otherwise resolved in source order. Recursively
4837
        // resolve a supertrait only when it is declared later.
4838
        if superSym.node.id > node.id {
4839
            let case ast::NodeValue::TraitDecl {
4840
                supertraits: inheritedTraits, methods: inheritedMethods, ..
4841
            } = superSym.node.value else throw emitError(self, superNode, ErrorKind::Internal);
4842
            try resolveTraitBody(self, superSym.node, inheritedTraits, inheritedMethods);
4843
        }
4844
4845
        setNodeSymbol(self, superNode, superSym);
4846
4847
        let a = alloc::arenaAllocator(self.arena);
4848
        if traitType.methods.len + superTrait.methods.len > ast::MAX_TRAIT_METHODS {
4849
            throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
4850
                expected: ast::MAX_TRAIT_METHODS,
4851
                actual: traitType.methods.len as u32 + superTrait.methods.len as u32,
4852
            }));
4853
        }
4854
        // Copy inherited methods into this trait's method table.
4855
        for inherited in superTrait.methods {
4856
            if let _ = findTraitMethod(traitType, inherited.name) {
4857
                throw emitError(self, superNode, ErrorKind::DuplicateBinding(inherited.name));
4858
            }
4859
            traitType.methods.append(TraitMethod {
4860
                name: inherited.name,
4861
                fnType: inherited.fnType,
4862
                mutable: inherited.mutable,
4863
                receiverClass: inherited.receiverClass,
4864
                index: traitType.methods.len as u32,
4865
            }, a);
4866
        }
4867
        traitType.supertraits.append(superTrait, a);
4868
    }
4869
4870
    if traitType.methods.len + methods.len > ast::MAX_TRAIT_METHODS {
4871
        throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
4872
            expected: ast::MAX_TRAIT_METHODS,
4873
            actual: traitType.methods.len as u32 + methods.len as u32,
4874
        }));
4875
    }
4876
4877
    for methodNode in methods {
4878
        let case ast::NodeValue::TraitMethodSig { name, modifiers, receiver, sig } = methodNode.value
4879
            else continue;
4880
        let attrs = modifiers.attrs;
4881
        let methodName = try nodeName(self, name);
4882
        let attrMask = resolveAttributes(attrs);
4883
        let previousRegions = self.regionScope;
4884
        set self.regionScope = try bindRegions(self, methodNode, modifiers.regions);
4885
4886
        // Reject duplicate method names.
4887
        if let _ = findTraitMethod(traitType, methodName) {
4888
            throw emitError(self, name, ErrorKind::DuplicateBinding(methodName));
4889
        }
4890
        // Determine the receiver class and mutability, and validate that it
4891
        // points to the declaring trait.
4892
        let case ast::NodeValue::TypeSig(typeSig) = receiver.value
4893
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
4894
        let case ast::TypeSig::Pointer {
4895
            class: receiverSyntax, valueType: receiverValueType, mutable,
4896
        } = typeSig
4897
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
4898
        let receiverClass = resolvePointerClass(receiverSyntax);
4899
        let case ast::NodeValue::TypeSig(innerSig) = receiverValueType.value
4900
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
4901
        let case ast::TypeSig::Nominal(nameNode) = innerSig
4902
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
4903
        let receiverTargetName = try nodeName(self, nameNode);
4904
4905
        if receiverTargetName <> traitType.name {
4906
            throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
4907
        }
4908
        // Resolve parameter types and return type.
4909
        let a = alloc::arenaAllocator(self.arena);
4910
        let mut paramTypes: *mut [*Type] = &mut [];
4911
        let mut throwList: *mut [*Type] = &mut [];
4912
        let mut retType = allocType(self, Type::Void);
4913
4914
        if sig.params.len > MAX_FN_PARAMS {
4915
            throw emitError(self, methodNode, ErrorKind::FnParamOverflow(CountMismatch {
4916
                expected: MAX_FN_PARAMS,
4917
                actual: sig.params.len,
4918
            }));
4919
        }
4920
        for paramNode in sig.params {
4921
            let case ast::NodeValue::FnParam(param) = paramNode.value
4922
                else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
4923
            let paramTy = try resolveValueType(self, param.type);
4924
            paramTypes.append(allocType(self, paramTy), a);
4925
        }
4926
        if let ret = sig.returnType {
4927
            set retType = allocType(self, try infer(self, ret));
4928
        }
4929
        // Resolve throws list.
4930
        if sig.throwList.len > MAX_FN_THROWS {
4931
            throw emitError(self, methodNode, ErrorKind::FnThrowOverflow(CountMismatch {
4932
                expected: MAX_FN_THROWS,
4933
                actual: sig.throwList.len,
4934
            }));
4935
        }
4936
        for throwNode in sig.throwList {
4937
            let throwTy = try infer(self, throwNode);
4938
            try validateErrorTag(self, throwNode, throwTy, &throwList[..]);
4939
            throwList.append(allocType(self, throwTy), a);
4940
        }
4941
        let fnType = FnType {
4942
            regions: self.regionScope,
4943
            paramTypes: &paramTypes[..],
4944
            returnType: retType,
4945
            throwList: &throwList[..],
4946
            isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe),
4947
        };
4948
        traitType.methods.append(TraitMethod {
4949
            name: methodName,
4950
            fnType: allocFnType(self, fnType),
4951
            mutable,
4952
            receiverClass,
4953
            index: traitType.methods.len as u32,
4954
        }, a);
4955
4956
        setNodeType(self, methodNode, Type::Void);
4957
        set self.regionScope = previousRegions;
4958
    }
4959
}
4960
4961
/// Resolve a name path node to a symbol.
4962
/// Used for trait and type references in instance declarations and trait objects.
4963
unsafe fn resolveNamePath 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> *unsafe mut Symbol
4964
    throws (ResolveError)
4965
{
4966
    match node.value {
4967
        case ast::NodeValue::Ident(name) => {
4968
            let sym = findAnySymbol(self.scope, name)
4969
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
4970
            return sym;
4971
        }
4972
        case ast::NodeValue::ScopeAccess(access) => {
4973
            let scope = self.scope;
4974
            return try resolveAccess(self, node, access, scope);
4975
        }
4976
        else => {
4977
            throw emitError(self, node, ErrorKind::ExpectedIdentifier);
4978
        }
4979
    }
4980
}
4981
4982
/// Join instance and method region parameters into one function binder.
4983
unsafe fn instanceMethodRegions 'arena (
4984
    self: &mut Resolver 'arena, instanceRegions: *[*ast::Node], methodRegions: *[*ast::Node]
4985
) -> *[*ast::Node] {
4986
    let count = instanceRegions.len + methodRegions.len;
4987
    if count == 0 {
4988
        return &[];
4989
    }
4990
    let allocator = alloc::arenaAllocator(self.arena);
4991
    let mut nodes: *mut [*ast::Node] = &mut [];
4992
    for region in instanceRegions {
4993
        nodes.append(region, allocator);
4994
    }
4995
    for region in methodRegions {
4996
        nodes.append(region, allocator);
4997
    }
4998
    return &nodes[..];
4999
}
5000
5001
/// Map one region binder to a contiguous part of another binder.
5002
unsafe fn mapRegionScopes 'arena (
5003
    self: &mut Resolver 'arena, source: ?*RegionScope, target: ?*RegionScope,
5004
    offset: u32, site: *ast::Node
5005
) -> ?RegionSubstitution throws (ResolveError) {
5006
    let sourceScope = source else return nil;
5007
    let targetScope = target else throw emitError(self, site, ErrorKind::Internal);
5008
    if offset + sourceScope.entries.len > targetScope.entries.len {
5009
        throw emitError(self, site, ErrorKind::RegionArgumentCount(CountMismatch {
5010
            expected: sourceScope.entries.len,
5011
            actual: targetScope.entries.len - offset,
5012
        }));
5013
    }
5014
    let map = regionSubstitution(self, sourceScope);
5015
    for _, i in sourceScope.entries {
5016
        set map.arguments[i] = targetScope.entries[offset + i];
5017
    }
5018
    try validateRegionArguments(self, &map, site);
5019
    return map;
5020
}
5021
5022
/// Resolved implementation of one trait method.
5023
record ResolvedInstanceMethod: Copy {
5024
    /// Canonical trait method.
5025
    method: *unsafe TraitMethod,
5026
    /// Concrete function symbol.
5027
    symbol: *unsafe mut Symbol,
5028
}
5029
5030
/// Shared declaration state for instance method resolution.
5031
record InstanceMethodContext: Copy {
5032
    /// Implemented trait.
5033
    traitInfo: *unsafe TraitType,
5034
    /// Instance target with declaration regions applied.
5035
    concreteType: Type,
5036
    /// Instance region nodes in declaration order.
5037
    regions: *[*ast::Node],
5038
    /// Bound instance region scope.
5039
    scope: ?*RegionScope,
5040
}
5041
5042
/// Resolve one instance method in its combined region environment.
5043
unsafe fn resolveInstanceMethod 'arena (
5044
    self: &mut Resolver 'arena, methodNode: *ast::Node,
5045
    context: &InstanceMethodContext
5046
) -> ResolvedInstanceMethod throws (ResolveError) {
5047
    let case ast::NodeValue::MethodDecl {
5048
        name, modifiers, receiverType, sig, ..
5049
    } = methodNode.value else panic "resolveInstanceMethod: invalid method";
5050
    let combinedRegions = instanceMethodRegions(self, context.regions, modifiers.regions);
5051
    let methodScope = try bindRegions(self, methodNode, combinedRegions);
5052
    set self.regionScope = methodScope;
5053
5054
    let methodName = try nodeName(self, name);
5055
    let attrMask = resolveAttributes(modifiers.attrs);
5056
    let tm = findTraitMethod(context.traitInfo, methodName)
5057
        else throw emitError(self, name, ErrorKind::UnresolvedSymbol(methodName));
5058
    if ast::hasAttribute(attrMask, ast::Attribute::Unsafe) <> tm.fnType.isUnsafe {
5059
        throw emitError(self, methodNode, ErrorKind::TraitMethodSafetyMismatch);
5060
    }
5061
5062
    let case ast::NodeValue::TypeSig(ast::TypeSig::Pointer {
5063
        class: receiverSyntax, valueType, mutable: receiverMut,
5064
    }) = receiverType.value else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
5065
    let receiverClass = resolvePointerClass(receiverSyntax);
5066
    if receiverClass <> tm.receiverClass {
5067
        throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
5068
    }
5069
    let annotatedTy = try infer(self, valueType);
5070
    let mut expectedConcrete = context.concreteType;
5071
    if let map = try mapRegionScopes(self, context.scope, methodScope, 0, methodNode) {
5072
        set expectedConcrete = substituteRegions(self, &map, context.concreteType);
5073
    }
5074
    if not typesEqual(annotatedTy, expectedConcrete) {
5075
        throw emitTypeMismatch(self, receiverType, TypeMismatch { expected: expectedConcrete, actual: annotatedTy });
5076
    }
5077
    if tm.mutable and not receiverMut {
5078
        throw emitError(self, receiverType, ErrorKind::ImmutableBinding);
5079
    }
5080
    if receiverMut and not tm.mutable {
5081
        throw emitError(self, receiverType, ErrorKind::ReceiverMutabilityMismatch);
5082
    }
5083
5084
    let mut traitFn = tm.fnType;
5085
    let mut traitRegionCount: u32 = 0;
5086
    if let traitScope = tm.fnType.regions {
5087
        set traitRegionCount = traitScope.entries.len;
5088
    }
5089
    if traitRegionCount <> modifiers.regions.len {
5090
        throw emitError(self, methodNode, ErrorKind::RegionArgumentCount(CountMismatch {
5091
            expected: traitRegionCount, actual: modifiers.regions.len,
5092
        }));
5093
    }
5094
    if let map = try mapRegionScopes(self, tm.fnType.regions, methodScope, context.regions.len, methodNode) {
5095
        set traitFn = substituteFnRegions(self, &map, tm.fnType, nil);
5096
    }
5097
    if sig.params.len <> traitFn.paramTypes.len {
5098
        throw emitError(self, methodNode, ErrorKind::FnArgCountMismatch(CountMismatch {
5099
            expected: traitFn.paramTypes.len, actual: sig.params.len,
5100
        }));
5101
    }
5102
5103
    let allocator = alloc::arenaAllocator(self.arena);
5104
    let mut paramTypes: *mut [*Type] = &mut [];
5105
    let receiverPtrType = Type::Pointer {
5106
        class: receiverClass, target: allocType(self, annotatedTy), mutable: receiverMut,
5107
    };
5108
    paramTypes.append(allocType(self, receiverPtrType), allocator);
5109
    for paramNode, i in sig.params {
5110
        let case ast::NodeValue::FnParam(param) = paramNode.value
5111
            else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
5112
        let instanceParamTy = try resolveValueType(self, param.type);
5113
        if not typesEqual(instanceParamTy, *traitFn.paramTypes[i]) {
5114
            throw emitTypeMismatch(self, paramNode, TypeMismatch {
5115
                expected: *traitFn.paramTypes[i], actual: instanceParamTy,
5116
            });
5117
        }
5118
        paramTypes.append(allocType(self, instanceParamTy), allocator);
5119
    }
5120
    let mut returnType = Type::Void;
5121
    if let returnNode = sig.returnType {
5122
        set returnType = try resolveValueType(self, returnNode);
5123
    }
5124
    if not typesEqual(returnType, *traitFn.returnType) {
5125
        throw emitTypeMismatch(self, methodNode, TypeMismatch {
5126
            expected: *traitFn.returnType, actual: returnType,
5127
        });
5128
    }
5129
    if sig.throwList.len <> traitFn.throwList.len {
5130
        throw emitError(self, methodNode, ErrorKind::FnThrowCountMismatch(CountMismatch {
5131
            expected: traitFn.throwList.len, actual: sig.throwList.len,
5132
        }));
5133
    }
5134
    let mut throwList: *mut [*Type] = &mut [];
5135
    for throwNode, i in sig.throwList {
5136
        let throwType = try resolveValueType(self, throwNode);
5137
        if not typesEqual(throwType, *traitFn.throwList[i]) {
5138
            throw emitTypeMismatch(self, throwNode, TypeMismatch {
5139
                expected: *traitFn.throwList[i], actual: throwType,
5140
            });
5141
        }
5142
        throwList.append(allocType(self, throwType), allocator);
5143
    }
5144
5145
    let fnType = FnType {
5146
        regions: methodScope, paramTypes: &paramTypes[..],
5147
        returnType: allocType(self, returnType), throwList: &throwList[..],
5148
        isUnsafe: tm.fnType.isUnsafe,
5149
    };
5150
    let fnTy = Type::Fn(allocFnType(self, fnType));
5151
    let sym = allocSymbol(self, SymbolData::Value {
5152
        mutable: false, alignment: 0, type: fnTy, addressTaken: false,
5153
    }, methodName, methodNode, attrMask);
5154
    setNodeSymbol(self, methodNode, sym);
5155
    setNodeType(self, methodNode, fnTy);
5156
    setNodeType(self, name, fnTy);
5157
    set self.regionScope = context.scope;
5158
    return ResolvedInstanceMethod { method: tm, symbol: sym };
5159
}
5160
5161
/// Resolve an instance declaration.
5162
/// Validates that the trait exists, the target type exists, and all methods
5163
/// match the trait's signatures.
5164
unsafe fn resolveInstanceDecl 'arena (
5165
    self: &mut Resolver 'arena,
5166
    node: *ast::Node,
5167
    traitName: *ast::Node,
5168
    targetType: *ast::Node,
5169
    regions: *[*ast::Node],
5170
    methods: *[*ast::Node]
5171
) throws (ResolveError) {
5172
    let previous = self.regionScope;
5173
    set self.regionScope = try bindRegions(self, node, regions);
5174
    try resolveInstanceContents(self, node, traitName, targetType, regions, methods) catch error {
5175
        set self.regionScope = previous;
5176
        throw error;
5177
    };
5178
    set self.regionScope = previous;
5179
}
5180
5181
/// Resolve an instance in its declaration region environment.
5182
unsafe fn resolveInstanceContents 'arena (
5183
    self: &mut Resolver 'arena,
5184
    node: *ast::Node,
5185
    traitName: *ast::Node,
5186
    targetType: *ast::Node,
5187
    regions: *[*ast::Node],
5188
    methods: *[*ast::Node]
5189
) throws (ResolveError) {
5190
    let instanceScope = self.regionScope;
5191
    // Look up the trait.
5192
    let traitSym = try resolveNamePath(self, traitName);
5193
    let case SymbolData::Trait(traitInfo) = traitSym.data
5194
        else throw emitError(self, traitName, ErrorKind::Internal);
5195
5196
    setNodeSymbol(self, traitName, traitSym);
5197
5198
    // Look up the target type.
5199
    let typeSym = try resolveNamePath(self, targetType);
5200
    let case SymbolData::Type(nominalTy) = typeSym.data
5201
        else throw emitError(self, targetType, ErrorKind::Internal);
5202
    setNodeSymbol(self, targetType, typeSym);
5203
    // Ensure the concrete type body is resolved.
5204
    try ensureNominalResolved(self, nominalTy, targetType);
5205
5206
    // Reject duplicate instance for the same (trait, type) pair.
5207
    let mut concreteInfo = nominalTy;
5208
    if regions.len > 0 {
5209
        set concreteInfo = try applyNominalRegions(self, nominalTy, regions, targetType);
5210
    } else {
5211
        try requireNominalArguments(self, nominalTy, targetType);
5212
    }
5213
    let concreteType = Type::Nominal(concreteInfo);
5214
    if let _ = findInstance(self, traitInfo, concreteType) {
5215
        throw emitError(self, node, ErrorKind::DuplicateInstance);
5216
    }
5217
5218
    // Build the instance entry.
5219
    if self.instancesLen >= MAX_INSTANCES {
5220
        throw emitError(self, node, ErrorKind::Internal);
5221
    }
5222
    let methodSlice = try! alloc::allocRawSlice(
5223
        self.arena, @sizeOf(*unsafe mut Symbol), @alignOf(*unsafe mut Symbol), traitInfo.methods.len as u32
5224
    ) as *unsafe mut [*unsafe mut Symbol];
5225
    let mut entry = InstanceEntry {
5226
        traitType: traitInfo,
5227
        concreteType,
5228
        concreteTypeName: typeSym.name,
5229
        moduleId: self.currentMod,
5230
        methods: methodSlice,
5231
    };
5232
    // Track which trait methods are covered by the instance.
5233
    let mut covered: [bool; ast::MAX_TRAIT_METHODS] = [false; ast::MAX_TRAIT_METHODS];
5234
    let methodContext = InstanceMethodContext {
5235
        traitInfo, concreteType, regions, scope: instanceScope,
5236
    };
5237
5238
    // Match each instance method to a trait method.
5239
    for methodNode in methods {
5240
        let resolved = try resolveInstanceMethod(
5241
            self, methodNode, &methodContext
5242
        );
5243
        set entry.methods[resolved.method.index] = resolved.symbol;
5244
        set covered[resolved.method.index] = true;
5245
    }
5246
5247
    // Fill inherited method slots from supertrait instances.
5248
    for superTrait in traitInfo.supertraits {
5249
        let superInst = findInstance(self, superTrait, concreteType)
5250
            else throw emitError(self, node, ErrorKind::MissingSupertraitInstance(superTrait.name));
5251
        for superMethod, mi in superTrait.methods {
5252
            let merged = findTraitMethod(traitInfo, superMethod.name)
5253
                else panic "resolveInstanceDecl: inherited method not found";
5254
            if not covered[merged.index] {
5255
                set entry.methods[merged.index] = superInst.methods[mi];
5256
                set covered[merged.index] = true;
5257
            }
5258
        }
5259
    }
5260
5261
    // Check that all trait methods are implemented.
5262
    for method, i in traitInfo.methods {
5263
        if not covered[i] {
5264
            throw emitError(self, node, ErrorKind::MissingTraitMethod(method.name));
5265
        }
5266
    }
5267
    set self.instances[self.instancesLen] = entry;
5268
    set self.instancesLen += 1;
5269
5270
    setNodeType(self, node, Type::Void);
5271
}
5272
5273
/// Resolve instance method bodies.
5274
unsafe fn resolveInstanceMethodBodies 'arena (self: &mut Resolver 'arena, methods: *[*ast::Node])
5275
    throws (ResolveError)
5276
{
5277
    for methodNode in methods {
5278
        let case ast::NodeValue::MethodDecl { .. } = methodNode.value else continue;
5279
5280
        // Symbol may be absent if [`resolveInstanceDecl`] reported an error
5281
        // for this method (eg. unknown method name). Skip gracefully.
5282
        if symbolFor(self, methodNode) == nil {
5283
            continue;
5284
        }
5285
5286
        try resolveMethodBody(self, methodNode);
5287
    }
5288
}
5289
5290
/// Resolve a method body shared by instance methods and standalone methods.
5291
/// Binds the receiver and parameters, then type-checks the body.
5292
unsafe fn resolveMethodBody 'arena (
5293
    self: &mut Resolver 'arena,
5294
    node: *ast::Node,
5295
) throws (ResolveError) {
5296
    let case ast::NodeValue::MethodDecl { receiverName, sig, body, .. } = node.value
5297
        else panic "resolveMethodBody: invalid method";
5298
    let sym = symbolFor(self, node)
5299
        else throw emitError(self, node, ErrorKind::Internal);
5300
    let case SymbolData::Value { type: Type::Fn(fnType), .. } = sym.data
5301
        else panic "resolveMethodBody: expected value symbol";
5302
    let previous = self.regionScope;
5303
    set self.regionScope = fnType.regions;
5304
    try resolveExecutableBody(self, node, fnType, receiverName, sig.params, body) catch error {
5305
        set self.regionScope = previous;
5306
        throw error;
5307
    };
5308
    set self.regionScope = previous;
5309
}
5310
5311
/// Resolve a standalone method declaration (signature only).
5312
/// Validates the receiver type and registers the method in the method table.
5313
5314
/// Extract the type name from a resolved receiver type node.
5315
unsafe fn receiverTypeName 'arena (
5316
    self: &mut Resolver 'arena,
5317
    receiverType: *ast::Node,
5318
) -> *[u8] throws (ResolveError) {
5319
    let case ast::NodeValue::TypeSig(ast::TypeSig::Pointer { valueType, .. }) =
5320
        receiverType.value
5321
        else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
5322
    let mut nameNode: *ast::Node = valueType;
5323
    match valueType.value {
5324
        case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(name)) => set nameNode = name,
5325
        case ast::NodeValue::TypeSig(ast::TypeSig::Applied { name, .. }) => set nameNode = name,
5326
        else => throw emitError(self, receiverType, ErrorKind::Internal),
5327
    }
5328
    let sym = symbolFor(self, nameNode)
5329
        else throw emitError(self, receiverType, ErrorKind::Internal);
5330
5331
    return sym.name;
5332
}
5333
5334
/// Resolve and register a standalone method declaration.
5335
unsafe fn resolveMethodDecl 'arena (
5336
    self: &mut Resolver 'arena,
5337
    node: *ast::Node,
5338
) throws (ResolveError) {
5339
    let case ast::NodeValue::MethodDecl { modifiers, .. } = node.value
5340
        else panic "resolveMethodDecl: invalid method";
5341
    let previous = self.regionScope;
5342
    set self.regionScope = try bindRegions(self, node, modifiers.regions);
5343
    try resolveMethodSignature(self, node) catch error {
5344
        set self.regionScope = previous;
5345
        throw error;
5346
    };
5347
    set self.regionScope = previous;
5348
}
5349
5350
/// Resolve a standalone method signature in its region environment.
5351
unsafe fn resolveMethodSignature 'arena (
5352
    self: &mut Resolver 'arena,
5353
    node: *ast::Node,
5354
) throws (ResolveError) {
5355
    let case ast::NodeValue::MethodDecl {
5356
        name, modifiers, receiverType, sig, ..
5357
    } = node.value else panic "resolveMethodSignature: invalid method";
5358
    // Resolve the receiver type: must be `*Type` or `*mut Type` pointing to a
5359
    // nominal type.
5360
    let fullReceiverTy = try infer(self, receiverType);
5361
    let case Type::Pointer {
5362
        class: receiverClass, target: receiverTarget, mutable: receiverMut,
5363
    } = fullReceiverTy
5364
        else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
5365
    let concreteType = *receiverTarget;
5366
    let case Type::Nominal(nominalTy) = concreteType
5367
        else throw emitError(self, receiverType, ErrorKind::ExpectedRecord);
5368
    try ensureNominalResolved(self, nominalTy, receiverType);
5369
5370
    // Get the type name from the inner type node's symbol.
5371
    let typeName = try receiverTypeName(self, receiverType);
5372
    let methodName = try nodeName(self, name);
5373
    let attrMask = resolveAttributes(modifiers.attrs);
5374
5375
    // Reject duplicate method for the same (type, name).
5376
    if let _ = findMethod(self, concreteType, methodName) {
5377
        throw emitError(self, name, ErrorKind::DuplicateBinding(methodName));
5378
    }
5379
5380
    // Resolve parameter types.
5381
    let a = alloc::arenaAllocator(self.arena);
5382
    let mut paramTypes: *mut [*Type] = &mut [];
5383
5384
    // Receiver is the first parameter.
5385
    let receiverPtrType = Type::Pointer {
5386
        class: receiverClass,
5387
        target: allocType(self, concreteType),
5388
        mutable: receiverMut,
5389
    };
5390
    paramTypes.append(allocType(self, receiverPtrType), a);
5391
5392
    for paramNode in sig.params {
5393
        let case ast::NodeValue::FnParam(param) = paramNode.value
5394
            else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
5395
        let paramTy = try resolveValueType(self, param.type);
5396
        paramTypes.append(allocType(self, paramTy), a);
5397
    }
5398
5399
    // Resolve return type.
5400
    let mut returnType = Type::Void;
5401
    if let retNode = sig.returnType {
5402
        set returnType = try resolveValueType(self, retNode);
5403
    }
5404
5405
    // Resolve throw list.
5406
    let mut throwTypes: *mut [*Type] = &mut [];
5407
    for throwNode in sig.throwList {
5408
        let throwTy = try resolveValueType(self, throwNode);
5409
        try validateErrorTag(self, throwNode, throwTy, &throwTypes[..]);
5410
        throwTypes.append(allocType(self, throwTy), a);
5411
    }
5412
5413
    let retTypePtr = allocType(self, returnType);
5414
    let throwList = &throwTypes[..];
5415
5416
    let isUnsafe = ast::hasAttribute(attrMask, ast::Attribute::Unsafe);
5417
    // Full function type (receiver + params) for lowering.
5418
    let fullFnType = FnType {
5419
        regions: self.regionScope,
5420
        paramTypes: &paramTypes[..],
5421
        returnType: retTypePtr,
5422
        throwList,
5423
        isUnsafe,
5424
    };
5425
    let fnTy = Type::Fn(allocFnType(self, fullFnType));
5426
5427
    // Function type excluding receiver, for call arg checking.
5428
    let checkFnType = FnType {
5429
        regions: self.regionScope,
5430
        paramTypes: &paramTypes[1..],
5431
        returnType: retTypePtr,
5432
        throwList,
5433
        isUnsafe,
5434
    };
5435
5436
    // Create a symbol for the method without binding it into the module scope.
5437
    let sym = allocSymbol(self, SymbolData::Value {
5438
        mutable: false, alignment: 0, type: fnTy, addressTaken: false,
5439
    }, methodName, node, attrMask);
5440
5441
    setNodeSymbol(self, node, sym);
5442
    setNodeType(self, node, fnTy);
5443
    setNodeType(self, name, fnTy);
5444
5445
    // Register in the method table.
5446
    if self.methodsLen >= MAX_METHODS {
5447
        throw emitError(self, node, ErrorKind::Internal);
5448
    }
5449
    set self.methods[self.methodsLen] = MethodEntry {
5450
        concreteType,
5451
        concreteTypeName: typeName,
5452
        name: methodName,
5453
        fnType: allocFnType(self, checkFnType),
5454
        mutable: receiverMut,
5455
        receiverClass,
5456
        symbol: sym,
5457
    };
5458
    set self.methodsLen += 1;
5459
}
5460
5461
/// Look up an instance entry by trait and concrete type.
5462
unsafe fn findInstance 'arena (self: &Resolver 'arena, traitInfo: *unsafe TraitType, concreteType: Type) -> ?*unsafe InstanceEntry {
5463
    for i in 0..self.instancesLen {
5464
        let entry: *unsafe InstanceEntry = &self.instances[i];
5465
        if entry.traitType == traitInfo and erasedTypesEqual(entry.concreteType, concreteType) {
5466
            return entry;
5467
        }
5468
    }
5469
    return nil;
5470
}
5471
5472
/// Look up a standalone method by concrete type and name.
5473
export unsafe fn findMethod 'arena (self: &Resolver 'arena, concreteType: Type, name: *[u8]) -> ?*unsafe MethodEntry {
5474
    for i in 0..self.methodsLen {
5475
        let entry: *unsafe MethodEntry = &self.methods[i];
5476
        if erasedTypesEqual(entry.concreteType, concreteType) and entry.name == name {
5477
            return entry;
5478
        }
5479
    }
5480
    return nil;
5481
}
5482
5483
/// Look up a standalone method entry by its symbol.
5484
export unsafe fn findMethodBySymbol 'arena (self: &Resolver 'arena, sym: *unsafe mut Symbol) -> ?*unsafe MethodEntry {
5485
    for i in 0..self.methodsLen {
5486
        let entry: *unsafe MethodEntry = &self.methods[i];
5487
        if entry.symbol == sym {
5488
            return entry;
5489
        }
5490
    }
5491
    return nil;
5492
}
5493
5494
/// Resolve union variant types after all type names are bound (Phase 2 of type resolution).
5495
unsafe fn resolveUnionBody 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::UnionDecl)
5496
    throws (ResolveError)
5497
{
5498
    let previous = self.regionScope;
5499
    set self.regionScope = try bindRegions(self, node, decl.regions);
5500
    try resolveUnionContents(self, node, decl) catch error {
5501
        set self.regionScope = previous;
5502
        throw error;
5503
    };
5504
    set self.regionScope = previous;
5505
}
5506
5507
/// Resolve union contents in the declaration's region environment.
5508
unsafe fn resolveUnionContents 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::UnionDecl)
5509
    throws (ResolveError)
5510
{
5511
    // Get the type symbol that was bound to this declaration node.
5512
    // If there's no symbol, it's because an earlier phase failed.
5513
    let sym = symbolFor(self, node)
5514
        else return;
5515
    let case SymbolData::Type(nominalTy) = sym.data
5516
        else panic "resolveUnionBody: unexpected symbol data";
5517
5518
    // Check if already resolved, in which case there's no need to
5519
    // do it again.
5520
    if let case NominalType::Union(_) = *nominalTy {
5521
        return;
5522
    }
5523
    let a = alloc::arenaAllocator(self.arena);
5524
    let mut variants: *unsafe mut [UnionVariant] = &mut [];
5525
5526
    let markers = try resolveOwnershipMarkers(self, decl.derives);
5527
    set *nominalTy = NominalType::Resolving(node);
5528
5529
    assert decl.variants.len <= MAX_UNION_VARIANTS, "resolveUnionBody: maximum union variants exceeded";
5530
    let mut iota: u32 = 0;
5531
    for variantNode, i in decl.variants {
5532
        let case ast::NodeValue::UnionDeclVariant(variantDecl) = variantNode.value
5533
            else panic "resolveUnionBody: invalid union variant";
5534
        let variantName = try nodeName(self, variantDecl.name);
5535
        // Resolve the variant's payload type if present.
5536
        let mut variantType = Type::Void;
5537
        if let typeNode = variantDecl.type {
5538
            set variantType = try infer(self, typeNode);
5539
            try ensureStorableType(self, typeNode, variantType);
5540
            try ensureTypeResolved(self, variantType, typeNode);
5541
        }
5542
        // Process the variant's explicit discriminant value if present.
5543
        try visitOptional(self, variantDecl.value, variantType);
5544
        let tag = variantTag(variantDecl, &mut iota);
5545
        // Create a symbol for this variant.
5546
        let data = SymbolData::Variant { type: variantType, decl: node, ordinal: i, index: tag };
5547
        let variantSym = allocSymbol(self, data, variantName, variantNode, 0);
5548
5549
        variants.append(UnionVariant {
5550
            name: variantName,
5551
            valueType: variantType,
5552
            symbol: variantSym,
5553
        }, a);
5554
    }
5555
    if markers.copy {
5556
        for variant in variants {
5557
            if not isCopy(variant.valueType) {
5558
                throw emitError(self, node, ErrorKind::CopyContainsNonCopy);
5559
            }
5560
        }
5561
    }
5562
    let info = computeUnionLayout(&variants[..]);
5563
5564
    // Update the nominal type with the resolved variants.
5565
    set *nominalTy = NominalType::Union(UnionType {
5566
        regions: self.regionScope,
5567
        application: nil,
5568
        variants: &variants[..],
5569
        layout: allocLayout(self, info.layout),
5570
        valOffset: info.valOffset,
5571
        isAllVoid: info.isAllVoid,
5572
        declaredLinear: markers.linear,
5573
        declaredCopy: markers.copy,
5574
    });
5575
}
5576
5577
/// Check whether an attributed module or import is active in this build.
5578
/// A test module is active only when its source module was registered.
5579
unsafe fn shouldAnalyzeModule 'arena (self: &Resolver 'arena, attrs: ?ast::Attributes, name: ?*[u8]) -> bool {
5580
    if let attributes = attrs {
5581
        if ast::attributesContains(&attributes, ast::Attribute::Test) {
5582
            if not self.config.buildTest {
5583
                return false;
5584
            }
5585
            if let moduleName = name {
5586
                return module::findChild(self.moduleGraph, moduleName, self.currentMod) <> nil;
5587
            }
5588
        }
5589
    }
5590
    return true;
5591
}
5592
5593
/// Analyze a module during the graph analysis phase.
5594
unsafe fn resolveModGraph 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::Mod)
5595
    throws (ResolveError)
5596
{
5597
    let modName = try nodeName(self, decl.name);
5598
    if not shouldAnalyzeModule(self, decl.attrs, modName) {
5599
        return;
5600
    }
5601
    let attrMask = resolveAttributes(decl.attrs);
5602
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
5603
    let submod = try enterSubModule(self, modName, node);
5604
5605
    // Bind the module symbol in the outer scope, ie. where the `mod` statement is.
5606
    try bindModuleIdent(self, submod.entry, submod.newScope, submod.root, attrMask, submod.prevScope);
5607
    let case ast::NodeValue::Block(block) = submod.root.value
5608
        else panic "resolveModGraph: expected block for module root";
5609
    try resolveModuleGraph(self, &block);
5610
5611
    exitModuleScope(self, submod);
5612
}
5613
5614
/// Analyze a module in the declaration phase.
5615
unsafe fn resolveModDecl 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::Mod)
5616
    throws (ResolveError)
5617
{
5618
    // Find module under the current module.
5619
    let modName = try nodeName(self, decl.name);
5620
    if not shouldAnalyzeModule(self, decl.attrs, modName) {
5621
        return;
5622
    }
5623
    let submod = try enterSubModule(self, modName, node);
5624
    let case ast::NodeValue::Block(block) = submod.root.value
5625
        else panic "resolveModDecl: expected block for module root";
5626
    try resolveModuleDecls(self, &block);
5627
5628
    exitModuleScope(self, submod);
5629
}
5630
5631
/// Analyze a `use` statement and create a symbol for the imported module.
5632
unsafe fn resolveUse 'arena (self: &mut Resolver 'arena, node: *ast::Node, decl: ast::Use) -> Type
5633
    throws (ResolveError)
5634
{
5635
    if not shouldAnalyzeModule(self, decl.attrs, nil) {
5636
        return Type::Void;
5637
    }
5638
    let resolved = try resolveModulePath(self, decl.path);
5639
    let attrMask = resolveAttributes(decl.attrs);
5640
5641
    if decl.wildcard {
5642
        // Import all public symbols from the target module.
5643
        for i in 0..resolved.scope.symbolsLen {
5644
            let sym = resolved.scope.symbols[i];
5645
            if ast::hasAttribute(sym.attrs, ast::Attribute::Export) {
5646
                if let existing = findSymbolInScope(self.scope, sym.name) {
5647
                    if existing == sym {
5648
                        continue;
5649
                    }
5650
                }
5651
                let scope = self.scope;
5652
                try addSymbolToScope(self, sym, scope, node);
5653
            }
5654
        }
5655
    } else {
5656
        // Regular module import.
5657
        let scope = self.scope;
5658
        try bindModuleIdent(self, resolved.entry, resolved.scope, node, attrMask, scope);
5659
    }
5660
    return Type::Void;
5661
}
5662
5663
/// Analyze a standard `if` statement.
5664
unsafe fn resolveIf 'arena (self: &mut Resolver 'arena, node: *ast::Node, cond: ast::If) -> Type
5665
    throws (ResolveError)
5666
{
5667
    try checkBoolean(self, cond.condition);
5668
    let thenTy = try visit(self, cond.thenBranch, Type::Void);
5669
    let elseTy = try visitOptional(self, cond.elseBranch, Type::Void);
5670
5671
    return setNodeType(self, node, unifyBranches(thenTy, elseTy));
5672
}
5673
5674
/// Analyze a conditional expression.
5675
unsafe fn resolveCondExpr 'arena (self: &mut Resolver 'arena, node: *ast::Node, cond: ast::CondExpr, hint: Type) -> Type
5676
    throws (ResolveError)
5677
{
5678
    try checkBoolean(self, cond.condition);
5679
    let thenValue = try visit(self, cond.thenExpr, hint);
5680
    let thenTy = assignableValueType(self, cond.thenExpr, thenValue);
5681
    let elseValue = try visit(self, cond.elseExpr, hint);
5682
    let elseTy = assignableValueType(self, cond.elseExpr, elseValue);
5683
5684
    // Either branch may supply the concrete type for an otherwise context-
5685
    // dependent expression, such as an unsuffixed integer or `nil`.
5686
    if let coercion = isAssignable(self, thenTy, elseTy, cond.elseExpr) {
5687
        setNodeCoercion(self, cond.elseExpr, coercion);
5688
        return setNodeType(self, node, thenTy);
5689
    }
5690
    if let coercion = isAssignable(self, elseTy, thenTy, cond.thenExpr) {
5691
        setNodeCoercion(self, cond.thenExpr, coercion);
5692
        return setNodeType(self, node, elseTy);
5693
    }
5694
    try expectAssignable(self, thenTy, elseTy, cond.elseExpr);
5695
5696
    return setNodeType(self, node, thenTy);
5697
}
5698
5699
/// Analyze a pattern match structure (used by if-let, while-let).
5700
unsafe fn resolvePatternMatch 'arena (self: &mut Resolver 'arena, node: *ast::Node, pat: &ast::PatternMatch)
5701
    throws (ResolveError)
5702
{
5703
    match pat.kind {
5704
        case ast::PatternKind::Case => {
5705
            // Analyze pattern against scrutinee type.
5706
            let scrutineeTy = try infer(self, pat.scrutinee);
5707
            if isUnsafePointerType(scrutineeTy) {
5708
                try requireUnsafe(self, pat.scrutinee);
5709
            }
5710
            let subject = unwrapMatchSubject(scrutineeTy);
5711
            try resolveCasePattern(self, pat.pattern, subject.effectiveTy, IdentMode::Compare, subject.by);
5712
        }
5713
        case ast::PatternKind::Binding => {
5714
            // Scrutinee must be optional, bind the payload.
5715
            let scrutineeTy = try checkOptional(self, pat.scrutinee);
5716
            let payloadTy = *scrutineeTy;
5717
5718
            try bindValueIdent(self, pat.pattern, node, payloadTy, pat.mutable, 0, 0);
5719
            setNodeType(self, pat.pattern, payloadTy);
5720
        }
5721
    }
5722
    if let guard = pat.guard {
5723
        try checkBoolean(self, guard);
5724
    }
5725
}
5726
5727
/// Analyze an `if let` or `if let case` pattern binding.
5728
unsafe fn resolveIfLet 'arena (self: &mut Resolver 'arena, node: *ast::Node, cond: ast::IfLet) -> Type
5729
    throws (ResolveError)
5730
{
5731
    enterScope(self, node);
5732
    try resolvePatternMatch(self, node, &cond.pattern);
5733
5734
    let thenTy = try visit(self, cond.thenBranch, Type::Void);
5735
    exitScope(self);
5736
5737
    let elseTy = try visitOptional(self, cond.elseBranch, Type::Void);
5738
5739
    return setNodeType(self, node, unifyBranches(thenTy, elseTy));
5740
}
5741
5742
/// Controls how bare identifiers are handled in case patterns.
5743
union IdentMode: Copy {
5744
    /// Identifier is a value to compare against.
5745
    Compare,
5746
    /// Identifier introduces a new binding.
5747
    Bind,
5748
}
5749
5750
/// Check whether a pattern node is a destructuring pattern that looks
5751
/// through structure (union variant, record literal, scope access).
5752
/// Identifiers, placeholders, and plain literals are not destructuring.
5753
export fn isDestructuringPattern(pattern: *ast::Node) -> bool {
5754
    match pattern.value {
5755
        case ast::NodeValue::Call(_),
5756
             ast::NodeValue::RecordLit(_),
5757
             ast::NodeValue::ScopeAccess(_) => return true,
5758
        else => return false,
5759
    }
5760
}
5761
5762
/// Analyze a case pattern for match, if-case, let-case, or while-case.
5763
///
5764
/// At the top level, bare identifiers are compared against existing values.
5765
/// Inside destructuring patterns (arrays, records), identifiers become bindings.
5766
unsafe fn resolveCasePattern 'arena (
5767
    self: &mut Resolver 'arena,
5768
    pattern: *ast::Node,
5769
    scrutineeTy: Type,
5770
    mode: IdentMode,
5771
    matchBy: MatchBy
5772
) throws (ResolveError) {
5773
    if let case Type::Pointer { target, .. } = scrutineeTy; isDestructuringPattern(pattern) {
5774
        if isUnsafePointerType(scrutineeTy) {
5775
            try requireUnsafe(self, pattern);
5776
        }
5777
        try resolveCasePattern(self, pattern, *target, mode, matchBy);
5778
        return;
5779
    }
5780
    // TODO: Collapse these nested matches.
5781
    match scrutineeTy {
5782
        case Type::Nominal(info) => {
5783
            try ensureNominalResolved(self, info, pattern);
5784
5785
            match *info {
5786
                case NominalType::Union(unionType) => {
5787
                    try resolveUnionPattern(self, pattern, scrutineeTy, unionType, matchBy);
5788
                    return;
5789
                }
5790
                case NominalType::Record(recInfo) => {
5791
                    match pattern.value {
5792
                        case ast::NodeValue::Call(_), ast::NodeValue::RecordLit(_) => {
5793
                            try resolveRecordPattern(self, pattern, scrutineeTy, recInfo, matchBy);
5794
                            return;
5795
                        } else => {}
5796
                    }
5797
                } else => {}
5798
            }
5799
        }
5800
        case Type::Array(arrayInfo) => {
5801
            if let case ast::NodeValue::ArrayLit(items) = pattern.value {
5802
                if items.len as u32 <> arrayInfo.length {
5803
                    throw emitError(self, pattern, ErrorKind::RecordFieldCountMismatch(
5804
                        CountMismatch { expected: arrayInfo.length, actual: items.len as u32 }
5805
                    ));
5806
                }
5807
                let elemTy = *arrayInfo.item;
5808
                for item in items {
5809
                    try resolveCasePattern(self, item, elemTy, IdentMode::Bind, matchBy);
5810
                }
5811
                setNodeType(self, pattern, scrutineeTy);
5812
                return;
5813
            }
5814
        } else => {}
5815
    }
5816
    // Handle non-binding patterns (literals, placeholders) and bindings.
5817
    match pattern.value {
5818
        case ast::NodeValue::Placeholder => {
5819
            // Placeholder matches without introducing bindings.
5820
        }
5821
        case ast::NodeValue::Ident(_) => {
5822
            match mode {
5823
                case IdentMode::Bind => try bindPatternVar(self, pattern, scrutineeTy, matchBy),
5824
                case IdentMode::Compare => try checkAssignable(self, pattern, scrutineeTy),
5825
            }
5826
        }
5827
        else => {
5828
            // Literals and other expressions: check type compatibility.
5829
            try checkAssignable(self, pattern, scrutineeTy);
5830
        }
5831
    }
5832
}
5833
5834
/// Analyze a traditional `while` loop.
5835
unsafe fn resolveWhile 'arena (self: &mut Resolver 'arena, node: *ast::Node, loopNode: ast::While) -> Type
5836
    throws (ResolveError)
5837
{
5838
    try checkBoolean(self, loopNode.condition);
5839
    let loopTy = try visitLoop(self, loopNode.body);
5840
    try visitOptional(self, loopNode.elseBranch, Type::Void);
5841
5842
    if loopNode.condition.value == ast::NodeValue::Bool(true) {
5843
        return setNodeType(self, node, loopTy);
5844
    }
5845
    return setNodeType(self, node, Type::Void);
5846
}
5847
5848
/// Analyze a `while let` loop with pattern binding.
5849
unsafe fn resolveWhileLet 'arena (self: &mut Resolver 'arena, node: *ast::Node, loopNode: ast::WhileLet) -> Type
5850
    throws (ResolveError)
5851
{
5852
    enterScope(self, node);
5853
    try resolvePatternMatch(self, node, &loopNode.pattern);
5854
5855
    try visitLoop(self, loopNode.body);
5856
    exitScope(self);
5857
5858
    try visitOptional(self, loopNode.elseBranch, Type::Void);
5859
5860
    return setNodeType(self, node, Type::Void);
5861
}
5862
5863
/// Analyze a `for` loop, binding iteration variables.
5864
unsafe fn resolveFor 'arena (self: &mut Resolver 'arena, node: *ast::Node, forStmt: ast::For) -> Type
5865
    throws (ResolveError)
5866
{
5867
    let iterableTy = try infer(self, forStmt.iterable);
5868
5869
    // Extract binding names for the lowerer.
5870
    let mut bindingName: ?*[u8] = nil;
5871
    if let case ast::NodeValue::Ident(name) = forStmt.binding.value {
5872
        set bindingName = name;
5873
    }
5874
    let mut indexName: ?*[u8] = nil;
5875
    if let idx = forStmt.index {
5876
        if let case ast::NodeValue::Ident(name) = idx.value {
5877
            set indexName = name;
5878
        }
5879
    }
5880
    // Extract item type and store pre-computed loop metadata for the lowerer.
5881
    let mut itemTy: Type = undefined;
5882
    match iterableTy {
5883
        case Type::Slice { item, .. } => {
5884
            set itemTy = *item;
5885
            setForLoopInfo(self, node, ForLoopInfo::Collection {
5886
                elemType: item, length: nil, bindingName, indexName
5887
            });
5888
        }
5889
        case Type::Range { start, .. } => {
5890
            // Iterable ranges must have a start, and since we enforce type
5891
            // equality for start and end, that is always the item type.
5892
            let valType = start else {
5893
                throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable);
5894
            };
5895
            let case ast::NodeValue::Range(range) = forStmt.iterable.value else {
5896
                throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable);
5897
            };
5898
            set itemTy = *valType;
5899
5900
            setForLoopInfo(self, node, ForLoopInfo::Range {
5901
                valType, range, bindingName, indexName
5902
            });
5903
        }
5904
        case Type::Array(arrayInfo) => {
5905
            set itemTy = *arrayInfo.item;
5906
            setForLoopInfo(self, node, ForLoopInfo::Collection {
5907
                elemType: arrayInfo.item,
5908
                length: arrayInfo.length,
5909
                bindingName,
5910
                indexName,
5911
            });
5912
        }
5913
        else => throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable),
5914
    }
5915
    enterScope(self, node);
5916
    try bindForLoopPattern(self, forStmt.binding, itemTy, false);
5917
5918
    if let pat = forStmt.index {
5919
        try bindForLoopPattern(self, pat, Type::U32, false);
5920
    }
5921
    // The lowerer always creates at least one internal variable for iteration,
5922
    // even when the binding is a placeholder or no explicit index is given.
5923
    if let owner = self.currentFnNode {
5924
        set self.nodeData.entries[owner.id].localCount += 1;
5925
    }
5926
    try visitLoop(self, forStmt.body);
5927
    exitScope(self);
5928
5929
    try visitOptional(self, forStmt.elseBranch, Type::Void);
5930
5931
    return setNodeType(self, node, Type::Void);
5932
}
5933
5934
/// Get the node within a pattern that carries the `UnionVariant` extra.
5935
/// For `ScopeAccess` it is the pattern itself, for `RecordLit` it is the
5936
/// type name, and for `Call` it is the callee.
5937
export fn patternVariantKeyNode(pattern: *ast::Node) -> ?*ast::Node {
5938
    match pattern.value {
5939
        case ast::NodeValue::ScopeAccess(_) => return pattern,
5940
        case ast::NodeValue::RecordLit(lit) => return lit.typeName,
5941
        case ast::NodeValue::Call(call) => return call.callee,
5942
        else => return nil,
5943
    }
5944
}
5945
5946
/// Get the i-th sub-pattern element from a compound pattern.
5947
/// For `RecordLit` this is the i-th field's value; for `Call` it is the
5948
/// i-th argument.
5949
fn patternSubElement(pattern: *ast::Node, idx: u32) -> ?*ast::Node {
5950
    match pattern.value {
5951
        case ast::NodeValue::RecordLit(lit) => {
5952
            if idx < lit.fields.len as u32 {
5953
                if let case ast::NodeValue::RecordLitField(field) = lit.fields[idx].value {
5954
                    return field.value;
5955
                }
5956
            }
5957
        }
5958
        case ast::NodeValue::Call(call) => {
5959
            if idx < call.args.len as u32 {
5960
                return call.args[idx];
5961
            }
5962
        }
5963
        else => {}
5964
    }
5965
    return nil;
5966
}
5967
5968
/// Get the number of sub-pattern elements in a compound pattern.
5969
fn patternSubCount(pattern: *ast::Node) -> u32 {
5970
    match pattern.value {
5971
        case ast::NodeValue::RecordLit(lit) => return lit.fields.len as u32,
5972
        case ast::NodeValue::Call(call) => return call.args.len as u32,
5973
        else => return 0,
5974
    }
5975
}
5976
5977
/// Check whether a pattern contains nested sub-patterns that further
5978
/// refine the match beyond the outer variant (e.g. nested union variant
5979
/// tests or literal comparisons). Used to allow the same outer variant
5980
/// to appear in multiple match arms.
5981
fn hasNestedRefiningPattern 'arena (self: &Resolver 'arena, pattern: *ast::Node) -> bool {
5982
    for i in 0..patternSubCount(pattern) {
5983
        if let sub = patternSubElement(pattern, i) {
5984
            if isRefiningPattern(self, sub) {
5985
                return true;
5986
            }
5987
        }
5988
    }
5989
    return false;
5990
}
5991
5992
/// Check whether a single pattern node is a refining pattern that tests
5993
/// a value rather than just binding it. Union variants, literals, and
5994
/// scope accesses are refining; identifiers, placeholders, and plain
5995
/// record destructurings are not.
5996
fn isRefiningPattern 'arena (self: &Resolver 'arena, pattern: *ast::Node) -> bool {
5997
    match pattern.value {
5998
        case ast::NodeValue::Ident(_), ast::NodeValue::Placeholder =>
5999
            return false,
6000
        case ast::NodeValue::RecordLit(_), ast::NodeValue::Call(_) => {
6001
            if let keyNode = patternVariantKeyNode(pattern) {
6002
                if let case NodeExtra::UnionVariant { .. } = self.nodeData.entries[keyNode.id].extra {
6003
                    return true;
6004
                }
6005
            }
6006
            // Plain record destructuring / non-variant call is not directly
6007
            // refining; recurse to check sub-patterns.
6008
            return hasNestedRefiningPattern(self, pattern);
6009
        }
6010
        case ast::NodeValue::ArrayLit(items) => {
6011
            for item in items {
6012
                if isRefiningPattern(self, item) {
6013
                    return true;
6014
                }
6015
            }
6016
            return false;
6017
        }
6018
        case ast::NodeValue::ScopeAccess(_) =>
6019
            return true,
6020
        else =>
6021
            return true,
6022
    }
6023
}
6024
6025
/// Check whether any pattern in a case prong matches unconditionally.
6026
/// A plain `_` or an all-binding array pattern (e.g. `[x, y]`) qualifies.
6027
/// Note: top-level identifiers in `case` are comparisons, not bindings,
6028
/// so they do not count as wildcards.
6029
fn hasWildcardPattern(patterns: *[*ast::Node]) -> bool {
6030
    for pattern in patterns {
6031
        match pattern.value {
6032
            case ast::NodeValue::Placeholder => return true,
6033
            case ast::NodeValue::ArrayLit(items) => {
6034
                if isIrrefutableArrayPattern(items) {
6035
                    return true;
6036
                }
6037
            }
6038
            else => {}
6039
        }
6040
    }
6041
    return false;
6042
}
6043
6044
/// Check whether all elements of an array pattern are irrefutable.
6045
/// Inside array patterns, identifiers are bindings, not comparisons.
6046
fn isIrrefutableArrayPattern(items: *[*ast::Node]) -> bool {
6047
    for item in items {
6048
        match item.value {
6049
            case ast::NodeValue::Ident(_), ast::NodeValue::Placeholder => {}
6050
            case ast::NodeValue::ArrayLit(inner) => {
6051
                if not isIrrefutableArrayPattern(inner) {
6052
                    return false;
6053
                }
6054
            }
6055
            else => return false,
6056
        }
6057
    }
6058
    return true;
6059
}
6060
6061
/// Analyze a match prong, checking for duplicate catch-alls. Returns the
6062
/// unified match type.
6063
unsafe fn resolveMatchProng 'arena (
6064
    self: &mut Resolver 'arena,
6065
    prongNode: *ast::Node,
6066
    prong: ast::MatchProng,
6067
    subjectTy: Type,
6068
    state: &mut MatchState,
6069
    matchType: Type,
6070
    matchBy: MatchBy
6071
) -> Type throws (ResolveError) {
6072
    // Whether this prong is catch-all.
6073
    let mut isCatchAll = false;
6074
6075
    if prong.guard <> nil {
6076
        set state.isConst = false;
6077
    } else {
6078
        match prong.arm {
6079
            case ast::ProngArm::Binding(_),
6080
                 ast::ProngArm::Else => set isCatchAll = true,
6081
            case ast::ProngArm::Case(patterns) => set isCatchAll = hasWildcardPattern(patterns),
6082
        }
6083
    }
6084
    if isCatchAll {
6085
        if state.catchAll {
6086
            throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll);
6087
        }
6088
        set state.catchAll = true;
6089
    }
6090
    setProngCatchAll(self, prongNode, isCatchAll);
6091
6092
    return try visitMatchProng(self, prongNode, prong, subjectTy, matchType, matchBy);
6093
}
6094
6095
/// Analyze a `match` expression. Dispatches to specialized functions based on
6096
/// the subject type.
6097
unsafe fn resolveMatch 'arena (self: &mut Resolver 'arena, node: *ast::Node, sw: ast::Match) -> Type
6098
    throws (ResolveError)
6099
{
6100
    let subjectTy = try infer(self, sw.subject);
6101
    if isUnsafePointerType(subjectTy) {
6102
        try requireUnsafe(self, sw.subject);
6103
    }
6104
    let subject = unwrapMatchSubject(subjectTy);
6105
6106
    if let case Type::Optional(inner) = subject.effectiveTy {
6107
        try resolveMatchOptional(self, node, sw, inner, subject.by);
6108
    } else if let case Type::Nominal(NominalType::Union(u)) = subject.effectiveTy {
6109
        try resolveMatchUnion(self, node, sw, subject.effectiveTy, u, subject.by);
6110
    } else {
6111
        try resolveMatchGeneric(self, node, sw, subject.effectiveTy, subject.by);
6112
    }
6113
6114
    // Mark last non-guarded prong as exhaustive.
6115
    let lastProng = sw.prongs[sw.prongs.len - 1];
6116
    let case ast::NodeValue::MatchProng(p) = lastProng.value
6117
        else panic "resolveMatch: expected match prong";
6118
    if p.guard == nil {
6119
        setProngCatchAll(self, lastProng, true);
6120
    }
6121
    let ty = typeFor(self, node) else {
6122
        return Type::Void;
6123
    };
6124
    return ty;
6125
}
6126
6127
/// Analyze a `match` expression on an optional subject.
6128
unsafe fn resolveMatchOptional 'arena (
6129
    self: &mut Resolver 'arena,
6130
    node: *ast::Node,
6131
    sw: ast::Match,
6132
    innerTy: *Type,
6133
    matchBy: MatchBy
6134
) -> Type throws (ResolveError)
6135
{
6136
    let subjectTy = Type::Optional(innerTy);
6137
    let prongs = sw.prongs;
6138
    let mut hasValue = false;
6139
    let mut hasNil = false;
6140
    let mut catchAll = false;
6141
    let mut matchType = Type::Never;
6142
6143
    for prongNode in prongs {
6144
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
6145
            else panic "resolveMatchOptional: expected match prong";
6146
6147
        let mut isCatchAll = false;
6148
        if prong.guard == nil {
6149
            match prong.arm {
6150
                case ast::ProngArm::Else => set isCatchAll = true,
6151
                case ast::ProngArm::Case(patterns) => set isCatchAll = hasWildcardPattern(patterns),
6152
                case ast::ProngArm::Binding(_) => {
6153
                    // For optionals, a binding does *not* always match.
6154
                }
6155
            }
6156
        }
6157
        if isCatchAll {
6158
            if catchAll {
6159
                throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll);
6160
            }
6161
            set catchAll = true;
6162
        }
6163
        setProngCatchAll(self, prongNode, isCatchAll);
6164
        set matchType = try visitMatchProng(self, prongNode, prong, subjectTy, matchType, matchBy);
6165
6166
        // Track coverage. Guarded prongs don't count as covering a case.
6167
        if prong.guard == nil {
6168
            if let case ast::ProngArm::Binding(_) = prong.arm {
6169
                if hasValue {
6170
                    throw emitError(self, prongNode, ErrorKind::DuplicateMatchPattern);
6171
                }
6172
                set hasValue = true;
6173
            } else if let case ast::ProngArm::Case(patterns) = prong.arm {
6174
                for pat in patterns {
6175
                    if let case ast::NodeValue::Nil = pat.value {
6176
                        if hasNil {
6177
                            throw emitError(self, pat, ErrorKind::DuplicateMatchPattern);
6178
                        }
6179
                        set hasNil = true;
6180
                    }
6181
                }
6182
            }
6183
        }
6184
    }
6185
6186
    // Check exhaustiveness.
6187
    if not catchAll {
6188
        if not hasValue {
6189
            throw emitError(self, node, ErrorKind::OptionalMatchMissingValue);
6190
        }
6191
        if not hasNil {
6192
            throw emitError(self, node, ErrorKind::OptionalMatchMissingNil);
6193
        }
6194
    } else if hasValue and hasNil {
6195
        throw emitError(self, node, ErrorKind::UnreachableElse);
6196
    }
6197
    return setNodeType(self, node, matchType);
6198
}
6199
6200
/// Analyze a `match` expression on a union subject.
6201
unsafe fn resolveMatchUnion 'arena (
6202
    self: &mut Resolver 'arena,
6203
    node: *ast::Node,
6204
    sw: ast::Match,
6205
    subjectTy: Type,
6206
    info: UnionType,
6207
    matchBy: MatchBy
6208
) -> Type throws (ResolveError) {
6209
    let prongs = sw.prongs;
6210
    let mut covered: [bool; MAX_UNION_VARIANTS] = [false; MAX_UNION_VARIANTS];
6211
    let mut coveredCount: u32 = 0;
6212
    let mut state = MatchState { catchAll: false, isConst: false };
6213
    let mut matchType = Type::Never;
6214
6215
    for prongNode in prongs {
6216
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
6217
            else panic "resolveMatchUnion: expected match prong";
6218
6219
        set matchType = try resolveMatchProng(self, prongNode, prong, subjectTy, &mut state, matchType, matchBy);
6220
6221
        // Guarded prongs don't count as covering. Patterns with nested
6222
        // refining sub-patterns (e.g. matching different inner union variants)
6223
        // don't count as duplicates or as fully covering.
6224
        if prong.guard == nil {
6225
            if let case ast::ProngArm::Case(patterns) = prong.arm {
6226
                for pattern in patterns {
6227
                    if let case NodeExtra::UnionVariant { ordinal: ix, .. } = self.nodeData.entries[pattern.id].extra {
6228
                        if not hasNestedRefiningPattern(self, pattern) {
6229
                            if covered[ix] {
6230
                                throw emitError(self, pattern, ErrorKind::DuplicateMatchPattern);
6231
                            }
6232
                            set covered[ix] = true;
6233
                            set coveredCount += 1;
6234
                        }
6235
                    }
6236
                }
6237
            }
6238
        }
6239
    }
6240
    // Check that all variants are covered.
6241
    if not state.catchAll {
6242
        for variant, i in info.variants {
6243
            if not covered[i] {
6244
                throw emitError(
6245
                    self, node, ErrorKind::UnionMatchNonExhaustive(variant.name)
6246
                );
6247
            }
6248
        }
6249
    } else if coveredCount == info.variants.len as u32 {
6250
        throw emitError(self, node, ErrorKind::UnreachableElse);
6251
    }
6252
    return setNodeType(self, node, matchType);
6253
}
6254
6255
/// Analyze a `match` expression on a generic subject type. Requires exhaustiveness:
6256
/// booleans must cover both `true` and `false`, other types require a catch-all.
6257
unsafe fn resolveMatchGeneric 'arena (self: &mut Resolver 'arena, node: *ast::Node, sw: ast::Match, subjectTy: Type, matchBy: MatchBy) -> Type
6258
    throws (ResolveError)
6259
{
6260
    let prongs = sw.prongs;
6261
    let mut state = MatchState { catchAll: false, isConst: true };
6262
    let mut matchType = Type::Never;
6263
    let mut hasTrue = false;
6264
    let mut hasFalse = false;
6265
    let mut hasConstCase = false;
6266
6267
    for prongNode in prongs {
6268
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
6269
            else panic "resolveMatchGeneric: expected match prong";
6270
6271
        set matchType = try resolveMatchProng(
6272
            self, prongNode, prong, subjectTy, &mut state, matchType, matchBy
6273
        );
6274
        // Track boolean coverage. Guarded prongs don't count as covering.
6275
        if let case ast::ProngArm::Case(patterns) = prong.arm {
6276
            for p in patterns {
6277
                if prong.guard == nil {
6278
                    if let case ast::NodeValue::Bool(val) = p.value {
6279
                        if (val and hasTrue) or (not val and hasFalse) {
6280
                            throw emitError(self, p, ErrorKind::DuplicateMatchPattern);
6281
                        }
6282
                        if val {
6283
                            set hasTrue = true;
6284
                        } else {
6285
                            set hasFalse = true;
6286
                        }
6287
                    }
6288
                }
6289
                // Scalar constant patterns allow the match to be lowered
6290
                // to a switch instruction.
6291
                if let c = constValueEntry(self, p) {
6292
                    match c {
6293
                        case ConstValue::Bool(_), ConstValue::Char(_), ConstValue::Int(_) =>
6294
                            set hasConstCase = true,
6295
                        else =>
6296
                            set state.isConst = false,
6297
                    }
6298
                }
6299
            }
6300
        }
6301
    }
6302
6303
    // Check exhaustiveness.
6304
    if not state.catchAll {
6305
        if let case Type::Bool = subjectTy {
6306
            if not hasTrue {
6307
                throw emitError(self, node, ErrorKind::BoolMatchMissing(true));
6308
            }
6309
            if not hasFalse {
6310
                throw emitError(self, node, ErrorKind::BoolMatchMissing(false));
6311
            }
6312
        } else {
6313
            throw emitError(self, node, ErrorKind::MatchNonExhaustive);
6314
        }
6315
    } else if let case Type::Bool = subjectTy {
6316
        if hasTrue and hasFalse {
6317
            throw emitError(self, node, ErrorKind::UnreachableElse);
6318
        }
6319
    }
6320
    setMatchConst(self, node, state.isConst and hasConstCase);
6321
6322
    return setNodeType(self, node, matchType);
6323
}
6324
6325
/// Analyze a single `match` prong branch. Returns the unified match type.
6326
unsafe fn visitMatchProng 'arena (
6327
    self: &mut Resolver 'arena,
6328
    node: *ast::Node,
6329
    prongNode: ast::MatchProng,
6330
    subjectTy: Type,
6331
    matchType: Type,
6332
    matchBy: MatchBy
6333
) -> Type throws (ResolveError) {
6334
    enterScope(self, node);
6335
    let prongTy = try resolveMatchProngBody(self, prongNode, subjectTy, matchBy) catch e {
6336
        exitScope(self);
6337
        throw e;
6338
    };
6339
    exitScope(self);
6340
    setNodeType(self, node, prongTy);
6341
6342
    return unifyBranches(matchType, prongTy);
6343
}
6344
6345
/// Analyze the contents of a `match` prong while inside the prong scope.
6346
unsafe fn resolveMatchProngBody 'arena (
6347
    self: &mut Resolver 'arena,
6348
    prong: ast::MatchProng,
6349
    subjectTy: Type,
6350
    matchBy: MatchBy
6351
) -> Type throws (ResolveError) {
6352
    match prong.arm {
6353
        case ast::ProngArm::Binding(pat) => {
6354
            // For optionals, bind the unwrapped inner type.
6355
            let mut bindTy = subjectTy;
6356
            if let case Type::Optional(inner) = subjectTy {
6357
                set bindTy = *inner;
6358
            }
6359
            try bindPatternVar(self, pat, bindTy, matchBy);
6360
        }
6361
        case ast::ProngArm::Case(patterns) => {
6362
            for pattern in patterns {
6363
                try resolveCasePattern(self, pattern, subjectTy, IdentMode::Compare, matchBy);
6364
            }
6365
        }
6366
        case ast::ProngArm::Else => {}
6367
    }
6368
    if let g = prong.guard {
6369
        try checkBoolean(self, g);
6370
    }
6371
    return try visit(self, prong.body, Type::Void);
6372
}
6373
6374
/// Ensure a scope access pattern references a compatible union variant.
6375
unsafe fn resolveUnionScopePattern 'arena (
6376
    self: &mut Resolver 'arena,
6377
    pattern: *ast::Node,
6378
    access: ast::Access,
6379
    subjectTy: Type,
6380
    unionType: UnionType
6381
) throws (ResolveError) {
6382
    let patternTy = try visit(self, pattern, subjectTy);
6383
    if not isComparable(patternTy, subjectTy) {
6384
        throw emitTypeMismatch(self, pattern, TypeMismatch {
6385
            expected: subjectTy,
6386
            actual: patternTy,
6387
        });
6388
    }
6389
    let case NodeExtra::UnionVariant { ordinal: index, .. } = self.nodeData.entries[pattern.id].extra else {
6390
        throw emitError(self, pattern, ErrorKind::Internal);
6391
    };
6392
    let variant = &unionType.variants[index];
6393
    // If this variant has a payload, throw an error, since the user hasn't
6394
    // provided one.
6395
    if variant.valueType <> Type::Void {
6396
        throw emitError(self, pattern, ErrorKind::UnionVariantPayloadMissing(variant.name));
6397
    }
6398
}
6399
6400
/// Validate and bind a union constructor call used as a `match` pattern.
6401
unsafe fn resolveUnionCallPattern 'arena (
6402
    self: &mut Resolver 'arena,
6403
    pattern: *ast::Node,
6404
    call: ast::Call,
6405
    subjectTy: Type,
6406
    unionType: UnionType,
6407
    matchBy: MatchBy
6408
) throws (ResolveError) {
6409
    let calleeTy = try checkEqual(self, call.callee, subjectTy);
6410
    let case NodeExtra::UnionVariant { ordinal: index, tag } = self.nodeData.entries[call.callee.id].extra else {
6411
        throw emitError(self, call.callee, ErrorKind::Internal);
6412
    };
6413
    let variant = &unionType.variants[index];
6414
    // Copy variant index to the pattern node for the lowerer.
6415
    setVariantInfo(self, pattern, index, tag);
6416
6417
    if variant.valueType <> Type::Void {
6418
        try bindUnionPatternPayload(self, pattern, call, variant.name, variant.valueType, matchBy);
6419
    } else {
6420
        throw emitError(self, pattern, ErrorKind::UnionVariantPayloadUnexpected(variant.name));
6421
    }
6422
}
6423
6424
/// Bind the payload introduced by a union constructor pattern.
6425
unsafe fn bindUnionPatternPayload 'arena (
6426
    self: &mut Resolver 'arena,
6427
    pattern: *ast::Node,
6428
    call: ast::Call,
6429
    variantName: *[u8],
6430
    payloadTy: Type,
6431
    matchBy: MatchBy
6432
) throws (ResolveError) {
6433
    if call.args.len == 0 {
6434
        throw emitError(
6435
            self, pattern, ErrorKind::UnionVariantPayloadMissing(variantName)
6436
        );
6437
    }
6438
    // All variant payloads are records.
6439
    try ensureTypeResolved(self, payloadTy, pattern);
6440
    let recInfo = getRecord(payloadTy)
6441
        else panic "bindUnionPatternPayload: payload is not a record";
6442
6443
    try bindRecordPatternFields(self, pattern, recInfo, matchBy);
6444
}
6445
6446
/// Bind a pattern variable. For ref matches, wraps the type in a pointer.
6447
unsafe fn bindPatternVar 'arena (self: &mut Resolver 'arena, binding: *ast::Node, ty: Type, matchBy: MatchBy)
6448
    throws (ResolveError)
6449
{
6450
    let mut bindTy = ty;
6451
    match matchBy {
6452
        case MatchBy::Value => {}
6453
        case MatchBy::Ref => set bindTy = Type::Pointer {
6454
            class: types::PointerClass::Ref,
6455
            target: allocType(self, ty),
6456
            mutable: false,
6457
        },
6458
        case MatchBy::MutRef => set bindTy = Type::Pointer {
6459
            class: types::PointerClass::Ref,
6460
            target: allocType(self, ty),
6461
            mutable: true,
6462
        },
6463
    }
6464
    match binding.value {
6465
        case ast::NodeValue::Placeholder => {
6466
            // Nothing to do.
6467
        }
6468
        case ast::NodeValue::Ident(_) => {
6469
            try bindValueIdent(self, binding, binding, bindTy, false, 0, 0);
6470
        }
6471
        else => {
6472
            // Nested pattern: recursively resolve (record destructuring,
6473
            // union variant, scope access, call, literals, etc).
6474
            try resolveCasePattern(self, binding, ty, IdentMode::Bind, matchBy);
6475
        }
6476
    }
6477
}
6478
6479
/// Check a record pattern's exact nominal type before binding its fields.
6480
unsafe fn resolveRecordPattern 'arena (
6481
    self: &mut Resolver 'arena, pattern: *ast::Node, subjectTy: Type, body: RecordType, matchBy: MatchBy
6482
) throws (ResolveError) {
6483
    let mut name: ?*ast::Node = nil;
6484
    match pattern.value {
6485
        case ast::NodeValue::Call(call) => set name = call.callee,
6486
        case ast::NodeValue::RecordLit(lit) => set name = lit.typeName,
6487
        else => panic "resolveRecordPattern: expected record pattern",
6488
    }
6489
    if let typeName = name {
6490
        let actual = try visit(self, typeName, subjectTy);
6491
        let symbol = symbolFor(self, typeName) else throw emitError(self, typeName, ErrorKind::ExpectedRecord);
6492
        let case SymbolData::Type(_) = symbol.data else throw emitError(self, typeName, ErrorKind::ExpectedRecord);
6493
        if not typesEqual(actual, subjectTy) {
6494
            throw emitTypeMismatch(self, typeName, TypeMismatch { expected: subjectTy, actual });
6495
        }
6496
    }
6497
    setNodeType(self, pattern, subjectTy);
6498
    try bindRecordPatternFields(self, pattern, body, matchBy);
6499
}
6500
6501
/// Bind record pattern fields to variables in the current scope.
6502
unsafe fn bindRecordPatternFields 'arena (
6503
    self: &mut Resolver 'arena,
6504
    pattern: *ast::Node,
6505
    recInfo: RecordType,
6506
    matchBy: MatchBy
6507
) throws (ResolveError) {
6508
    match pattern.value {
6509
        case ast::NodeValue::Call(call) => {
6510
            // Unlabeled patterns: `S(x, y)`.
6511
            try checkRecordArity(self, call.args, recInfo, pattern);
6512
6513
            for binding, i in call.args {
6514
                let fieldType = recInfo.fields[i].fieldType;
6515
                try bindPatternVar(self, binding, fieldType, matchBy);
6516
            }
6517
        }
6518
        case ast::NodeValue::RecordLit(lit) => {
6519
            // Labeled patterns: `T { x, y }` or `T { x: binding }`.
6520
            if not lit.ignoreRest {
6521
                try checkRecordArity(self, lit.fields, recInfo, pattern);
6522
            }
6523
            for fieldNode in lit.fields {
6524
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
6525
                    else panic "expected RecordLitField";
6526
6527
                // Brace patterns require labeled fields.
6528
                let label = field.label else panic "expected labeled field";
6529
                let fieldName = try nodeName(self, label);
6530
                let fieldIndex = findRecordField(&recInfo, fieldName)
6531
                    else throw emitError(self, fieldNode, ErrorKind::RecordFieldUnknown(fieldName));
6532
                let fieldType = recInfo.fields[fieldIndex].fieldType;
6533
                // Store field index for the lowerer.
6534
                setRecordFieldIndex(self, fieldNode, fieldIndex);
6535
                try bindPatternVar(self, field.value, fieldType, matchBy);
6536
            }
6537
        }
6538
        else => throw emitError(self, pattern, ErrorKind::Internal)
6539
    }
6540
}
6541
6542
/// Validate and bind a record literal pattern for matching labeled union variants.
6543
unsafe fn resolveUnionRecordPattern 'arena (
6544
    self: &mut Resolver 'arena,
6545
    pattern: *ast::Node,
6546
    lit: ast::RecordLit,
6547
    subjectTy: Type,
6548
    unionType: UnionType,
6549
    matchBy: MatchBy
6550
) throws (ResolveError) {
6551
    let typeName = lit.typeName else {
6552
        throw emitError(self, pattern, ErrorKind::Internal);
6553
    };
6554
    // Verify the type matches the subject.
6555
    let patternTy = try visit(self, typeName, subjectTy);
6556
    if not isComparable(patternTy, subjectTy) {
6557
        throw emitTypeMismatch(self, pattern, TypeMismatch {
6558
            expected: subjectTy,
6559
            actual: patternTy,
6560
        });
6561
    }
6562
    let case NodeExtra::UnionVariant { ordinal: index, tag } = self.nodeData.entries[typeName.id].extra else {
6563
        throw emitError(self, typeName, ErrorKind::Internal);
6564
    };
6565
    let variant = &unionType.variants[index];
6566
6567
    // Copy variant index to the pattern node for the lowerer.
6568
    setVariantInfo(self, pattern, index, tag);
6569
6570
    if variant.valueType == Type::Void {
6571
        throw emitError(self, pattern, ErrorKind::UnionVariantPayloadUnexpected(variant.name));
6572
    }
6573
    try ensureTypeResolved(self, variant.valueType, pattern);
6574
    let recInfo = getRecord(variant.valueType)
6575
        else panic "resolveUnionRecordPattern: payload is not a record";
6576
6577
    try bindRecordPatternFields(self, pattern, recInfo, matchBy);
6578
}
6579
6580
/// Analyze a pattern appearing in a union case.
6581
unsafe fn resolveUnionPattern 'arena (
6582
    self: &mut Resolver 'arena,
6583
    pattern: *ast::Node,
6584
    subjectTy: Type,
6585
    unionType: UnionType,
6586
    matchBy: MatchBy
6587
) throws (ResolveError) {
6588
    match pattern.value {
6589
        case ast::NodeValue::ScopeAccess(access) =>
6590
            try resolveUnionScopePattern(self, pattern, access, subjectTy, unionType),
6591
        case ast::NodeValue::Call(call) =>
6592
            try resolveUnionCallPattern(self, pattern, call, subjectTy, unionType, matchBy),
6593
        case ast::NodeValue::RecordLit(lit) =>
6594
            try resolveUnionRecordPattern(self, pattern, lit, subjectTy, unionType, matchBy),
6595
        else => {
6596
            let patternTy = try visit(self, pattern, subjectTy);
6597
            throw emitTypeMismatch(self, pattern, TypeMismatch {
6598
                expected: subjectTy,
6599
                actual: patternTy,
6600
            });
6601
        }
6602
    }
6603
}
6604
6605
/// Return whether a case pattern introduces value bindings.
6606
fn casePatternIntroducesBindings(pattern: *ast::Node, nested: bool) -> bool {
6607
    match pattern.value {
6608
        case ast::NodeValue::Ident(_) => return nested,
6609
        case ast::NodeValue::Call(call) => {
6610
            for arg in call.args {
6611
                if casePatternIntroducesBindings(arg, true) {
6612
                    return true;
6613
                }
6614
            }
6615
        }
6616
        case ast::NodeValue::RecordLit(lit) => {
6617
            for fieldNode in lit.fields {
6618
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
6619
                    else continue;
6620
                if casePatternIntroducesBindings(field.value, true) {
6621
                    return true;
6622
                }
6623
            }
6624
        }
6625
        case ast::NodeValue::ArrayLit(items) => {
6626
            for item in items {
6627
                if casePatternIntroducesBindings(item, true) {
6628
                    return true;
6629
                }
6630
            }
6631
        }
6632
        else => {}
6633
    }
6634
    return false;
6635
}
6636
6637
/// Analyze a `let-else` guard.
6638
unsafe fn resolveLetElse 'arena (self: &mut Resolver 'arena, node: *ast::Node, letElse: ast::LetElse) -> Type
6639
    throws (ResolveError)
6640
{
6641
    let pat = letElse.pattern;
6642
    let exprTy = try infer(self, pat.scrutinee);
6643
6644
    match pat.kind {
6645
        case ast::PatternKind::Binding => {
6646
            // Simple binding requires an optional expression.
6647
            let case Type::Optional(inner) = exprTy else {
6648
                throw emitError(self, pat.scrutinee, ErrorKind::ExpectedOptional);
6649
            };
6650
            let payloadTy = *inner;
6651
            let _ = try bindValueIdent(self, pat.pattern, node, payloadTy, pat.mutable, 0, 0);
6652
            // The `else` branch supplies the binding when the optional is nil.
6653
            try checkAssignable(self, letElse.elseBranch, payloadTy);
6654
6655
            return setNodeType(self, node, Type::Void);
6656
        }
6657
        case ast::PatternKind::Case => {
6658
            // Resolve the failure path before introducing success-only bindings.
6659
            let elseTy = try checkAssignable(self, letElse.elseBranch, exprTy);
6660
            try resolveCasePattern(
6661
                self,
6662
                pat.pattern,
6663
                exprTy,
6664
                IdentMode::Compare,
6665
                MatchBy::Value,
6666
            );
6667
            if let guardExpr = pat.guard {
6668
                try checkBoolean(self, guardExpr);
6669
            }
6670
            if elseTy <> Type::Never and
6671
               casePatternIntroducesBindings(pat.pattern, false)
6672
            {
6673
                throw emitError(
6674
                    self,
6675
                    letElse.elseBranch,
6676
                    ErrorKind::LinearLetElseMustTerminate,
6677
                );
6678
            }
6679
        }
6680
    }
6681
    return setNodeType(self, node, Type::Void);
6682
}
6683
6684
/// Analyze builtin function calls like `@sizeOf(T)` and `@alignOf(T)`.
6685
unsafe fn resolveBuiltinCall 'arena (
6686
    self: &mut Resolver 'arena,
6687
    node: *ast::Node,
6688
    kind: ast::Builtin,
6689
    args: *[*ast::Node]
6690
) -> Type throws (ResolveError) {
6691
    // Handle `@sliceOf(ptr, len)` and `@sliceOf(ptr, len, cap)`.
6692
    if kind == ast::Builtin::SliceOf {
6693
        if args.len <> 2 and args.len <> 3 {
6694
            throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch {
6695
                expected: 2,
6696
                actual: args.len as u32,
6697
            }));
6698
        }
6699
        let ptrType = try visit(self, args[0], Type::Unknown);
6700
        let case Type::Pointer { class, target, mutable } = ptrType else {
6701
            throw emitError(self, node, ErrorKind::ExpectedPointer);
6702
        };
6703
        let _ = try checkAssignable(self, args[1], Type::U32);
6704
        if args.len == 3 {
6705
            let _ = try checkAssignable(self, args[2], Type::U32);
6706
        }
6707
        try requireUnsafe(self, node);
6708
        return setNodeType(self, node, Type::Slice { class, item: target, mutable });
6709
    }
6710
    if args.len <> 1 {
6711
        throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch {
6712
            expected: 1,
6713
            actual: args.len as u32,
6714
        }));
6715
    }
6716
6717
    let ty = try resolveValueType(self, args[0]);
6718
    // Ensure the type body is resolved before computing layout.
6719
    // TODO: Somehow, ensuring the type is resolved should just happen all
6720
    // the time, lazily.
6721
    try ensureTypeResolved(self, ty, args[0]);
6722
    // TODO: This should be stored in `symbol` instead of having to recompute it.
6723
    // That way there's a canonical place to look for code gen.
6724
    let layout = getTypeLayout(ty);
6725
6726
    // Evaluate the built-in.
6727
    let mut value: u32 = undefined;
6728
    match kind {
6729
        case ast::Builtin::SizeOf => {
6730
            set value = layout.size;
6731
        },
6732
        case ast::Builtin::AlignOf => {
6733
            set value = layout.alignment;
6734
        },
6735
        case ast::Builtin::SliceOf => {
6736
            panic "unreachable: @sliceOf handled above";
6737
        }
6738
    }
6739
    // Record as constant value for constant folding.
6740
    setNodeConstValue(self, node, ConstValue::Int(ConstInt {
6741
        magnitude: value as u64,
6742
        bits: 32,
6743
        signed: false,
6744
        negative: false,
6745
    }));
6746
    return setNodeType(self, node, Type::U32);
6747
}
6748
6749
/// Allocate an initially empty argument map for a region-parameterized signature.
6750
unsafe fn regionSubstitution 'arena (self: &mut Resolver 'arena, parameters: *RegionScope) -> RegionSubstitution {
6751
    let count = parameters.entries.len;
6752
    let arguments = try! alloc::allocRawSlice(
6753
        self.arena, @sizeOf(?*unsafe types::Region), @alignOf(?*unsafe types::Region), count
6754
    ) as *unsafe mut [?*unsafe types::Region];
6755
    for i in 0..count {
6756
        set arguments[i] = nil;
6757
    }
6758
    return RegionSubstitution { parameters, arguments };
6759
}
6760
6761
/// Find the position of a region in a substitution's declared parameter list.
6762
unsafe fn regionParameter(map: &RegionSubstitution, region: *unsafe types::Region) -> ?u32 {
6763
    for parameter, i in map.parameters.entries {
6764
        if parameter.id == region.id {
6765
            return i;
6766
        }
6767
    }
6768
    return nil;
6769
}
6770
6771
/// Infer one region argument from a pair of reference classes.
6772
unsafe fn inferRegionClass 'arena (
6773
    self: &mut Resolver 'arena, map: &RegionSubstitution,
6774
    expected: types::PointerClass, actual: types::PointerClass, site: *ast::Node
6775
) throws (ResolveError) {
6776
    let case types::PointerClass::Region(parameter) = expected else return;
6777
    let index = regionParameter(map, parameter) else return;
6778
    let case types::PointerClass::Region(argument) = actual
6779
        else throw emitError(self, site, ErrorKind::RegionInference(parameter.name));
6780
    if let previous = map.arguments[index]; previous.id <> argument.id {
6781
        throw emitError(self, site, ErrorKind::RegionInference(parameter.name));
6782
    }
6783
    set map.arguments[index] = argument;
6784
}
6785
6786
/// Infer regions through matching type structure without adding lifetime subtyping.
6787
unsafe fn inferRegionArguments 'arena (
6788
    self: &mut Resolver 'arena, map: &RegionSubstitution, expected: Type, actual: Type, site: *ast::Node
6789
) throws (ResolveError) {
6790
    match expected {
6791
        case Type::Cell { class, payload } => {
6792
            let case Type::Cell { class: otherClass, payload: other } = actual else return;
6793
            try inferRegionClass(self, map, class, otherClass, site);
6794
            try inferRegionArguments(self, map, *payload, *other, site);
6795
        }
6796
        case Type::Session(region) => {
6797
            let case Type::Session(other) = actual else return;
6798
            try inferRegionClass(self, map, types::PointerClass::Region(region),
6799
                types::PointerClass::Region(other), site);
6800
        }
6801
        case Type::Pointer { class, target, .. } => {
6802
            let case Type::Pointer { class: otherClass, target: otherTarget, .. } = actual else return;
6803
            try inferRegionClass(self, map, class, otherClass, site);
6804
            try inferRegionArguments(self, map, *target, *otherTarget, site);
6805
        }
6806
        case Type::Slice { class, item, .. } => {
6807
            let case Type::Slice { class: otherClass, item: otherItem, .. } = actual else return;
6808
            try inferRegionClass(self, map, class, otherClass, site);
6809
            try inferRegionArguments(self, map, *item, *otherItem, site);
6810
        }
6811
        case Type::TraitObject { class, .. } => {
6812
            if let case Type::TraitObject { class: otherClass, .. } = actual {
6813
                try inferRegionClass(self, map, class, otherClass, site);
6814
            }
6815
        }
6816
        case Type::Array(array) => {
6817
            if let case Type::Array(other) = actual {
6818
                try inferRegionArguments(self, map, *array.item, *other.item, site);
6819
            }
6820
        }
6821
        case Type::Optional(inner) => {
6822
            if let case Type::Optional(other) = actual {
6823
                try inferRegionArguments(self, map, *inner, *other, site);
6824
            } else {
6825
                try inferRegionArguments(self, map, *inner, actual, site);
6826
            }
6827
        }
6828
        case Type::Fn(info) => {
6829
            let case Type::Fn(other) = actual else return;
6830
            if info.paramTypes.len <> other.paramTypes.len or info.throwList.len <> other.throwList.len {
6831
                return;
6832
            }
6833
            for parameter, i in info.paramTypes {
6834
                try inferRegionArguments(self, map, *parameter, *other.paramTypes[i], site);
6835
            }
6836
            for error, i in info.throwList {
6837
                try inferRegionArguments(self, map, *error, *other.throwList[i], site);
6838
            }
6839
            try inferRegionArguments(self, map, *info.returnType, *other.returnType, site);
6840
        }
6841
        case Type::Nominal(info) => {
6842
            let applied = nominalApplication(info) else return;
6843
            let case Type::Nominal(otherInfo) = actual else return;
6844
            let other = nominalApplication(otherInfo) else return;
6845
            if applied.base <> other.base {
6846
                return;
6847
            }
6848
            for region, i in applied.arguments {
6849
                try inferRegionClass(self, map, types::PointerClass::Region(region),
6850
                    types::PointerClass::Region(other.arguments[i]), site);
6851
            }
6852
        }
6853
        else => {
6854
        }
6855
    }
6856
}
6857
6858
/// Require a total substitution whose arguments satisfy each parent relation.
6859
unsafe fn validateRegionArguments 'arena (self: &mut Resolver 'arena, map: &RegionSubstitution, site: *ast::Node)
6860
    throws (ResolveError)
6861
{
6862
    for parameter, i in map.parameters.entries {
6863
        if map.arguments[i] == nil {
6864
            throw emitError(self, site, ErrorKind::RegionInference(parameter.name));
6865
        }
6866
    }
6867
    for parameter, i in map.parameters.entries {
6868
        let parent = parameter.parent else continue;
6869
        let index = regionParameter(map, parent) else panic "validateRegionArguments: unknown parent";
6870
        let parentArgument = map.arguments[index] else panic "validateRegionArguments: missing parent argument";
6871
        let argument = map.arguments[i] else panic "validateRegionArguments: missing argument";
6872
        if not types::regionContains(parentArgument, argument) {
6873
            throw emitError(self, site, ErrorKind::RegionParent(parameter.name));
6874
        }
6875
    }
6876
}
6877
6878
/// Substitute a reference's region while preserving its ownership class.
6879
unsafe fn substituteRegionClass(map: &RegionSubstitution, class: types::PointerClass) -> types::PointerClass {
6880
    let case types::PointerClass::Region(region) = class else return class;
6881
    let index = regionParameter(map, region) else return class;
6882
    let argument = map.arguments[index] else panic "substituteRegionClass: missing argument";
6883
    return types::PointerClass::Region(argument);
6884
}
6885
6886
/// Substitute free region arguments in a type without changing its runtime layout.
6887
unsafe fn substituteRegions 'arena (self: &mut Resolver 'arena, map: &RegionSubstitution, ty: Type) -> Type {
6888
    match ty {
6889
        case Type::Cell { class, payload } =>
6890
            return Type::Cell { class: substituteRegionClass(map, class), payload: allocType(self, substituteRegions(self, map, *payload)) },
6891
        case Type::Session(region) => {
6892
            let index = regionParameter(map, region) else return ty;
6893
            let argument = map.arguments[index] else panic "substituteRegions: missing session region";
6894
            return Type::Session(argument);
6895
        }
6896
        case Type::Pointer { class, target, mutable } => {
6897
            let targetType = substituteRegions(self, map, *target);
6898
            return Type::Pointer { class: substituteRegionClass(map, class), target: allocType(self, targetType), mutable };
6899
        }
6900
        case Type::Slice { class, item, mutable } => {
6901
            let itemType = substituteRegions(self, map, *item);
6902
            return Type::Slice { class: substituteRegionClass(map, class), item: allocType(self, itemType), mutable };
6903
        }
6904
        case Type::TraitObject { class, traitInfo, mutable } =>
6905
            return Type::TraitObject { class: substituteRegionClass(map, class), traitInfo, mutable },
6906
        case Type::Array(array) => {
6907
            let itemType = substituteRegions(self, map, *array.item);
6908
            return Type::Array(ArrayType { item: allocType(self, itemType), length: array.length });
6909
        }
6910
        case Type::Optional(inner) => {
6911
            let innerType = substituteRegions(self, map, *inner);
6912
            return Type::Optional(allocType(self, innerType));
6913
        }
6914
        case Type::Fn(info) => return Type::Fn(substituteFnRegions(self, map, info, info.regions)),
6915
        case Type::Nominal(info) => {
6916
            let applied = nominalApplication(info) else return ty;
6917
            let arguments = regionSubstitution(self, applied.parameters);
6918
            for region, i in applied.arguments {
6919
                let class = substituteRegionClass(map, types::PointerClass::Region(region));
6920
                let case types::PointerClass::Region(argument) = class else panic;
6921
                set arguments.arguments[i] = argument;
6922
            }
6923
            return Type::Nominal(internNominalApplication(self, applied.base, &arguments));
6924
        }
6925
        else => return ty,
6926
    }
6927
}
6928
6929
/// Create a substituted signature with the specified remaining region binder.
6930
unsafe fn substituteFnRegions 'arena (
6931
    self: &mut Resolver 'arena, map: &RegionSubstitution, info: *FnType, regions: ?*RegionScope
6932
) -> *FnType {
6933
    let a = alloc::arenaAllocator(self.arena);
6934
    let mut paramTypes: *mut [*Type] = &mut [];
6935
    let mut throwList: *mut [*Type] = &mut [];
6936
    for parameter in info.paramTypes {
6937
        let ty = substituteRegions(self, map, *parameter);
6938
        paramTypes.append(allocType(self, ty), a);
6939
    }
6940
    for error in info.throwList {
6941
        let ty = substituteRegions(self, map, *error);
6942
        throwList.append(allocType(self, ty), a);
6943
    }
6944
    let returnType = substituteRegions(self, map, *info.returnType);
6945
    return allocFnType(self, FnType {
6946
        regions,
6947
        paramTypes: &paramTypes[..],
6948
        returnType: allocType(self, returnType),
6949
        throwList: &throwList[..],
6950
        isUnsafe: info.isUnsafe,
6951
    });
6952
}
6953
6954
/// Preserve a call-scoped pointer class while inferring its region-bearing contents.
6955
/// Named reference regions are inferred from the source storage.
6956
unsafe fn regionInputHint 'arena (self: &mut Resolver 'arena, expected: Type) -> Type {
6957
    if let case Type::Optional(inner) = expected {
6958
        return regionInputHint(self, *inner);
6959
    }
6960
    match expected {
6961
        case Type::Pointer { class, mutable, .. } => {
6962
            if let case types::PointerClass::Region(_) = class {
6963
                return Type::Unknown;
6964
            }
6965
            return Type::Pointer { class, target: allocType(self, Type::Unknown), mutable };
6966
        }
6967
        case Type::Slice { class, mutable, .. } => {
6968
            if let case types::PointerClass::Region(_) = class {
6969
                return Type::Unknown;
6970
            }
6971
            return Type::Slice { class, item: allocType(self, Type::Unknown), mutable };
6972
        }
6973
        else => return Type::Unknown,
6974
    }
6975
}
6976
6977
/// Infer a source function's region arguments from its call inputs.
6978
unsafe fn instantiateCall 'arena (self: &mut Resolver 'arena, node: *ast::Node, call: ast::Call, info: *FnType) -> *FnType
6979
    throws (ResolveError)
6980
{
6981
    let parameters = info.regions else return info;
6982
    if call.args.len <> info.paramTypes.len {
6983
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
6984
            expected: info.paramTypes.len, actual: call.args.len,
6985
        }));
6986
    }
6987
    let map = regionSubstitution(self, parameters);
6988
    for argument, i in call.args {
6989
        let expected = *info.paramTypes[i];
6990
        if containsRegion(expected) {
6991
            let actual = try visit(self, argument, regionInputHint(self, expected));
6992
            try inferRegionArguments(self, &map, expected, actual, argument);
6993
        }
6994
    }
6995
    try validateRegionArguments(self, &map, node);
6996
    return substituteFnRegions(self, &map, info, nil);
6997
}
6998
6999
/// Infer a method's region arguments from its receiver and call arguments.
7000
unsafe fn instantiateMethodCall 'arena (
7001
    self: &mut Resolver 'arena, node: *ast::Node, call: ast::Call,
7002
    receiver: *ast::Node, receiverType: Type, method: *unsafe MethodEntry
7003
) -> *FnType throws (ResolveError) {
7004
    let parameters = method.fnType.regions else return method.fnType;
7005
    if call.args.len <> method.fnType.paramTypes.len {
7006
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
7007
            expected: method.fnType.paramTypes.len, actual: call.args.len,
7008
        }));
7009
    }
7010
    let map = regionSubstitution(self, parameters);
7011
    try inferRegionArguments(self, &map, method.concreteType, receiverType, receiver);
7012
    for argument, i in call.args {
7013
        let expected = *method.fnType.paramTypes[i];
7014
        if containsRegion(expected) {
7015
            let actual = try visit(self, argument, regionInputHint(self, expected));
7016
            try inferRegionArguments(self, &map, expected, actual, argument);
7017
        }
7018
    }
7019
    try validateRegionArguments(self, &map, node);
7020
    return substituteFnRegions(self, &map, method.fnType, nil);
7021
}
7022
7023
/// Apply explicit current-scope regions to a function or nominal type.
7024
unsafe fn resolveRegionApply 'arena (
7025
    self: &mut Resolver 'arena, node: *ast::Node, value: *ast::Node, regions: *[*ast::Node]
7026
) -> Type throws (ResolveError) {
7027
    let ty = try infer(self, value);
7028
    if let case Type::Nominal(base) = ty {
7029
        let symbol = symbolFor(self, value) else throw emitError(self, node, ErrorKind::CannotInferType);
7030
        let case SymbolData::Type(_) = symbol.data else throw emitError(self, node, ErrorKind::CannotInferType);
7031
        let applied = try applyNominalRegions(self, base, regions, node);
7032
        try ensureNominalResolved(self, applied, node);
7033
        setNodeSymbol(self, node, symbol);
7034
        return setNodeType(self, node, Type::Nominal(applied));
7035
    }
7036
    let case Type::Fn(info) = ty else throw emitError(self, node, ErrorKind::CannotInferType);
7037
    let mut count: u32 = 0;
7038
    if let scope = info.regions {
7039
        set count = scope.entries.len;
7040
    }
7041
    if count <> regions.len {
7042
        throw emitError(self, node, ErrorKind::RegionArgumentCount(CountMismatch { expected: count, actual: regions.len }));
7043
    }
7044
    let scope = info.regions else panic "resolveRegionApply: empty region application";
7045
    let map = regionSubstitution(self, scope);
7046
    for region, i in regions {
7047
        set map.arguments[i] = try resolveRegion(self, region);
7048
    }
7049
    try validateRegionArguments(self, &map, node);
7050
    let applied = substituteFnRegions(self, &map, info, nil);
7051
    if let symbol = symbolFor(self, value) {
7052
        setNodeSymbol(self, node, symbol);
7053
    }
7054
    return setNodeType(self, node, Type::Fn(applied));
7055
}
7056
7057
/// Validate call arguments against a function type: check argument count,
7058
/// type-check each argument, and verify that throwing functions use `try`.
7059
unsafe fn checkCallArgs 'arena (self: &mut Resolver 'arena, node: *ast::Node, call: ast::Call, info: *FnType, ctx: CallCtx)
7060
    throws (ResolveError)
7061
{
7062
    if ctx == CallCtx::Normal and info.throwList.len > 0 {
7063
        throw emitError(self, node, ErrorKind::MissingTry);
7064
    }
7065
    if call.args.len <> info.paramTypes.len as u32 {
7066
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
7067
            expected: info.paramTypes.len as u32,
7068
            actual: call.args.len,
7069
        }));
7070
    }
7071
    for argNode, i in call.args {
7072
        let expectedTy = *info.paramTypes[i];
7073
7074
        try checkAssignable(self, argNode, expectedTy);
7075
    }
7076
}
7077
7078
/// Return whether a value can be discarded by bulk arena reclamation.
7079
/// Pointer lifetimes are checked when their values are constructed.
7080
unsafe fn isBulkDiscardable(ty: Type) -> bool {
7081
    match ty {
7082
        case Type::Void, Type::Bool, Type::U8, Type::U16, Type::U32, Type::U64,
7083
             Type::I8, Type::I16, Type::I32, Type::I64, Type::Fn(_) => return true,
7084
        case Type::Pointer { .. }, Type::Slice { .. }, Type::TraitObject { .. } => return true,
7085
        case Type::Cell { .. } => return true,
7086
        case Type::Array(array) => return isBulkDiscardable(*array.item),
7087
        case Type::Optional(inner) => return isBulkDiscardable(*inner),
7088
        case Type::Nominal(NominalType::Record(recordType)) => {
7089
            if recordType.declaredLinear {
7090
                return false;
7091
            }
7092
            for field in recordType.fields {
7093
                if not isBulkDiscardable(field.fieldType) {
7094
                    return false;
7095
                }
7096
            }
7097
            return true;
7098
        }
7099
        case Type::Nominal(NominalType::Union(unionType)) => {
7100
            if unionType.declaredLinear {
7101
                return false;
7102
            }
7103
            for variant in unionType.variants {
7104
                if not isBulkDiscardable(variant.valueType) {
7105
                    return false;
7106
                }
7107
            }
7108
            return true;
7109
        }
7110
        else => return false,
7111
    }
7112
}
7113
7114
/// Compute the end of an aligned layout within the allocator's byte-count range.
7115
fn allocationLayoutEnd(offset: u64, layout: Layout) -> ?u64 {
7116
    let mut aligned = offset;
7117
    if layout.alignment > 0 {
7118
        let mask = (layout.alignment - 1) as u64;
7119
        set aligned = (offset + mask) & ~mask;
7120
    }
7121
    let end = aligned + layout.size as u64;
7122
    if end > 4294967295 {
7123
        return nil;
7124
    }
7125
    return end;
7126
}
7127
7128
/// Check allocation layout arithmetic independently of the stored narrow offsets.
7129
unsafe fn hasAllocationLayout(ty: Type) -> bool {
7130
    let layout = getTypeLayout(ty);
7131
    match ty {
7132
        case Type::Cell { .. } => return true,
7133
        case Type::Array(array) => {
7134
            if not hasAllocationLayout(*array.item) {
7135
                return false;
7136
            }
7137
            let item = getTypeLayout(*array.item);
7138
            return item.size as u64 * array.length as u64 == layout.size as u64;
7139
        }
7140
        case Type::Optional(inner) => {
7141
            if not hasAllocationLayout(*inner) {
7142
                return false;
7143
            }
7144
            if isNullableType(*inner) {
7145
                return true;
7146
            }
7147
            let end = allocationLayoutEnd(1, getTypeLayout(*inner)) else return false;
7148
            let total = allocationLayoutEnd(end, Layout { size: 0, alignment: layout.alignment }) else return false;
7149
            return total == layout.size as u64;
7150
        }
7151
        case Type::Nominal(NominalType::Record(recordType)) => {
7152
            let mut offset: u64 = 0;
7153
            for field in recordType.fields {
7154
                if not hasAllocationLayout(field.fieldType) {
7155
                    return false;
7156
                }
7157
                let fieldLayout = getTypeLayout(field.fieldType);
7158
                let end = allocationLayoutEnd(offset, fieldLayout) else return false;
7159
                let start = end - fieldLayout.size as u64;
7160
                if start > 2147483647 or field.offset < 0 or start <> field.offset as u64 {
7161
                    return false;
7162
                }
7163
                set offset = end;
7164
            }
7165
            let total = allocationLayoutEnd(offset, Layout { size: 0, alignment: layout.alignment }) else return false;
7166
            return total == layout.size as u64;
7167
        }
7168
        case Type::Nominal(NominalType::Union(unionType)) => {
7169
            let mut payloadSize: u32 = 0;
7170
            let mut alignment: u32 = 1;
7171
            for variant in unionType.variants {
7172
                if not hasAllocationLayout(variant.valueType) {
7173
                    return false;
7174
                }
7175
                let item = getTypeLayout(variant.valueType);
7176
                set payloadSize = max(payloadSize, item.size);
7177
                set alignment = max(alignment, item.alignment);
7178
            }
7179
            let end = allocationLayoutEnd(1, Layout { size: payloadSize, alignment }) else return false;
7180
            let total = allocationLayoutEnd(end, Layout { size: 0, alignment }) else return false;
7181
            return total == layout.size as u64 and end - payloadSize as u64 == unionType.valOffset as u64;
7182
        }
7183
        else => return true,
7184
    }
7185
}
7186
7187
/// Validate the reservation ABI used by typed session allocation.
7188
unsafe fn sessionRuntime 'arena (
7189
    self: &mut Resolver 'arena, node: *ast::Node, slice: bool
7190
) -> *unsafe TraitMethod
7191
    throws (ResolveError)
7192
{
7193
    let allocTrait = allocationSymbol(self, "Alloc")
7194
        else throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7195
    let case SymbolData::Trait(allocInfo) = allocTrait.data
7196
        else throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7197
    let name = "reserveSlice" if slice else "reserve";
7198
    let method = findTraitMethod(allocInfo, name)
7199
        else throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7200
    let error = allocationSymbol(self, "AllocError")
7201
        else throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7202
    let case SymbolData::Type(errorType) = error.data
7203
        else throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7204
    let count: u32 = 3 if slice else 2;
7205
    let info = method.fnType;
7206
    if info.regions <> nil or not info.isUnsafe or info.paramTypes.len <> count or info.throwList.len <> 1 {
7207
        throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7208
    }
7209
    if not typesEqual(*info.throwList[0], Type::Nominal(errorType)) {
7210
        throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7211
    }
7212
    for i in 0..count {
7213
        if *info.paramTypes[i] <> Type::U32 {
7214
            throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7215
        }
7216
    }
7217
    let expected = Type::Slice { class: types::PointerClass::Unsafe, item: allocType(self, Type::Opaque), mutable: true }
7218
        if slice else Type::Pointer {
7219
            class: types::PointerClass::Unsafe, target: allocType(self, Type::Opaque), mutable: true
7220
        };
7221
    if not typesEqual(*info.returnType, expected) {
7222
        throw emitError(self, node, ErrorKind::InvalidAllocationRuntime);
7223
    }
7224
    return method;
7225
}
7226
7227
/// Check initialized session allocation and retain its source region in the result.
7228
unsafe fn resolveSessionAllocation 'arena (
7229
    self: &mut Resolver 'arena, node: *ast::Node, call: ast::Call, access: ast::Access,
7230
    region: *unsafe types::Region, ctx: CallCtx, hint: Type
7231
) -> Type throws (ResolveError) {
7232
    let name = try nodeName(self, access.child);
7233
    let mut kind = SessionAllocationKind::New;
7234
    if mem::eq(name, "copy") {
7235
        set kind = SessionAllocationKind::Copy;
7236
    }
7237
    else if mem::eq(name, "fill") {
7238
        set kind = SessionAllocationKind::Fill;
7239
    }
7240
    else if not mem::eq(name, "new") {
7241
        throw emitError(self, access.child, ErrorKind::UnresolvedSymbol(name));
7242
    }
7243
    let count: u32 = 2 if kind == SessionAllocationKind::Fill else 1;
7244
    if call.args.len <> count {
7245
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch { expected: count, actual: call.args.len }));
7246
    }
7247
    let slice = kind <> SessionAllocationKind::New;
7248
    let mut itemHint = Type::Unknown;
7249
    if kind == SessionAllocationKind::New {
7250
        if let case Type::Pointer { target, .. } = hint {
7251
            set itemHint = *target;
7252
        }
7253
    } else if kind == SessionAllocationKind::Fill {
7254
        if let case Type::Slice { item, .. } = hint {
7255
            set itemHint = *item;
7256
        }
7257
    } else {
7258
        set itemHint = Type::Slice {
7259
            class: types::PointerClass::Ref, item: allocType(self, Type::Unknown), mutable: false,
7260
        };
7261
    }
7262
    let valueType = try visit(self, call.args[0], itemHint);
7263
    let mut itemType = valueType;
7264
    let mut parameter = valueType;
7265
    if kind == SessionAllocationKind::Copy {
7266
        let case Type::Slice { item, .. } = valueType
7267
            else throw emitError(self, call.args[0], ErrorKind::ExpectedIndexable);
7268
        set itemType = *item;
7269
        set parameter = Type::Slice { class: types::PointerClass::Ref, item, mutable: false };
7270
    }
7271
    if not isTypeInferrable(itemType) or itemType == Type::Void or itemType == Type::Opaque {
7272
        throw emitError(self, call.args[0], ErrorKind::CannotInferType);
7273
    }
7274
    try ensureStorableType(self, call.args[0], itemType);
7275
    try ensureTypeResolved(self, itemType, call.args[0]);
7276
    try validateRegionStorage(self, call.args[0], itemType, region);
7277
    if not isBulkDiscardable(itemType) or (slice and not isCopy(itemType)) {
7278
        throw emitError(self, call.args[0], ErrorKind::InvalidAllocationValue);
7279
    }
7280
    if not hasAllocationLayout(itemType) {
7281
        throw emitError(self, call.args[0], ErrorKind::InvalidAllocationLayout);
7282
    }
7283
    let runtime = try sessionRuntime(self, node, slice);
7284
    let runtimeType = runtime.fnType;
7285
    let item = allocType(self, itemType);
7286
    let result = Type::Slice { class: types::PointerClass::Region(region), item, mutable: true }
7287
        if slice else Type::Pointer {
7288
            class: types::PointerClass::Region(region), target: item, mutable: true
7289
        };
7290
    let a = alloc::arenaAllocator(self.arena);
7291
    let mut parameters: *mut [*Type] = &mut [];
7292
    parameters.append(allocType(self, parameter), a);
7293
    if kind == SessionAllocationKind::Fill {
7294
        parameters.append(allocType(self, Type::U32), a);
7295
    }
7296
    let info = allocFnType(self, FnType {
7297
        regions: nil, paramTypes: &parameters[..], returnType: allocType(self, result),
7298
        throwList: runtimeType.throwList, isUnsafe: false,
7299
    });
7300
    try checkCallArgs(self, node, call, info, ctx);
7301
    setNodeType(self, call.callee, Type::Fn(info));
7302
    let allocTrait = allocationSymbol(self, "Alloc") else panic;
7303
    let case SymbolData::Trait(traitInfo) = allocTrait.data else panic;
7304
    set self.nodeData.entries[node.id].extra = NodeExtra::SessionAllocation(SessionAllocation {
7305
        kind, item, traitInfo, methodIndex: runtime.index,
7306
    });
7307
    return setNodeType(self, node, result);
7308
}
7309
7310
/// Return whether a nominal declaration explicitly derives Copy.
7311
fn nominalDeclaresCopy(node: *ast::Node) -> bool {
7312
    let mut derives: *[*ast::Node] = &[];
7313
    match node.value {
7314
        case ast::NodeValue::RecordDecl(decl) => set derives = decl.derives,
7315
        case ast::NodeValue::UnionDecl(decl) => set derives = decl.derives,
7316
        else => return false,
7317
    }
7318
    for derive in derives {
7319
        if let case ast::NodeValue::Ident(name) = derive.value {
7320
            if mem::eq(name, "Copy") {
7321
                return true;
7322
            }
7323
        }
7324
    }
7325
    return false;
7326
}
7327
7328
/// Require a complete payload that can be copied and discarded by value.
7329
unsafe fn validateCellPayload 'arena (self: &mut Resolver 'arena, node: *ast::Node, payload: Type) throws (ResolveError) {
7330
    try ensureStorableType(self, node, payload);
7331
    if let case Type::Nominal(info) = payload {
7332
        let mut source = info;
7333
        if let case NominalType::Application(applied) = *source {
7334
            set source = applied.base;
7335
        }
7336
        if let case NominalType::Resolving(decl) = *source {
7337
            if nominalDeclaresCopy(decl) {
7338
                return;
7339
            }
7340
            throw emitError(self, node, ErrorKind::InvalidCellPayload);
7341
        }
7342
    }
7343
    try ensureTypeResolved(self, payload, node);
7344
    if not isTypeInferrable(payload) or payload == Type::Void or payload == Type::Opaque
7345
        or not isCopy(payload) or not isBulkDiscardable(payload)
7346
    {
7347
        throw emitError(self, node, ErrorKind::InvalidCellPayload);
7348
    }
7349
    if not hasAllocationLayout(payload) {
7350
        throw emitError(self, node, ErrorKind::InvalidAllocationLayout);
7351
    }
7352
}
7353
7354
/// Analyze a function call expression.
7355
unsafe fn resolveCall 'arena (self: &mut Resolver 'arena, node: *ast::Node, call: ast::Call, ctx: CallCtx, hint: Type) -> Type
7356
    throws (ResolveError)
7357
{
7358
    // Intercept method calls on slices before inferring the callee.
7359
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
7360
        let parentTy = try infer(self, access.parent);
7361
        if isUnsafePointerType(parentTy) {
7362
            try requireUnsafe(self, access.parent);
7363
        }
7364
        let subjectTy = autoDeref(parentTy);
7365
        if let case Type::Session(region) = subjectTy {
7366
            return try resolveSessionAllocation(self, node, call, access, region, ctx, hint);
7367
        }
7368
7369
        if let case Type::Slice { item, mutable, .. } = subjectTy {
7370
            let methodName = try nodeName(self, access.child);
7371
            if methodName == "append" {
7372
                return try resolveSliceAppend(
7373
                    self, node, access.parent, parentTy, call.args, item, mutable
7374
                );
7375
            }
7376
            if methodName == "delete" {
7377
                return try resolveSliceDelete(
7378
                    self, node, access.parent, call.args, item, mutable
7379
                );
7380
            }
7381
        }
7382
    }
7383
    let calleeTy = try visit(self, call.callee, hint);
7384
    if let case Type::Fn(info) = calleeTy {
7385
        try checkUnsafeCall(self, call.callee, info);
7386
    }
7387
7388
    // Check if callee is a union variant and dispatch to constructor handler.
7389
    // TODO: Move this out. We should decide on this earlier, based on the callee.
7390
    if let calleeSym = symbolFor(self, call.callee) {
7391
        if let case SymbolData::Variant { decl, .. } = calleeSym.data {
7392
            // TODO: Don't pass the callee type, pass the union type by getting it from
7393
            // the symbol.
7394
            let case Type::Nominal(ty) = calleeTy else panic "resolveCall: invalid variant type";
7395
            return try resolveUnionConstructorCall(self, node, call, ty);
7396
        }
7397
        // Check if callee is an unlabeled record type for constructor call syntax.
7398
        if let case SymbolData::Type(_) = calleeSym.data {
7399
            let case Type::Nominal(ty) = calleeTy else panic "resolveCall: invalid type callee";
7400
            try requireNominalArguments(self, ty, call.callee);
7401
            // Ensure the record body is resolved before checking if labeled.
7402
            try ensureNominalResolved(self, ty, call.callee);
7403
            if let case NominalType::Record(recInfo) = *ty {
7404
                if not recInfo.labeled {
7405
                    return try resolveRecordConstructorCall(self, node, call, ty);
7406
                }
7407
            }
7408
        }
7409
    }
7410
7411
    // Check if we have a trait method call, ie. callee is a trait object.
7412
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
7413
        let mut parentTy = Type::Unknown;
7414
        if let t = typeFor(self, access.parent) {
7415
            set parentTy = t;
7416
        }
7417
        let subjectTy = autoDeref(parentTy);
7418
7419
        if let case Type::TraitObject { traitInfo, mutable: objMutable, .. } = subjectTy {
7420
            let methodName = try nodeName(self, access.child);
7421
            let method = findTraitMethod(traitInfo, methodName)
7422
                else throw emitError(self, access.child, ErrorKind::RecordFieldUnknown(methodName));
7423
7424
            // Reject mutable-receiver methods called on immutable trait objects.
7425
            if method.mutable {
7426
                if not objMutable or not try canMutateThrough(self, access.parent) {
7427
                    throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
7428
                }
7429
            }
7430
            let applied = try instantiateCall(self, node, call, method.fnType);
7431
            try checkCallArgs(self, node, call, applied, ctx);
7432
            setTraitMethodCall(self, node, traitInfo, method.index);
7433
7434
            return setNodeType(self, node, *applied.returnType);
7435
        }
7436
7437
        // Check for a standalone method call on a concrete type.
7438
        if let case Type::Nominal(_) = subjectTy {
7439
            let methodName = try nodeName(self, access.child);
7440
            if let method = findMethod(self, subjectTy, methodName) {
7441
                // Reject mutable-receiver methods on immutable bindings.
7442
                // If the parent is already a mutable pointer, the receiver is fine.
7443
                // Otherwise, check that the parent can yield a mutable borrow.
7444
                if method.mutable {
7445
                    if not try canMutateThrough(self, access.parent) {
7446
                        throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
7447
                    }
7448
                }
7449
                // Check arguments (excluding receiver).
7450
                let applied = try instantiateMethodCall(
7451
                    self, node, call, access.parent, subjectTy, method
7452
                );
7453
                try checkCallArgs(self, node, call, applied, ctx);
7454
                set self.nodeData.entries[node.id].extra = NodeExtra::MethodCall { method };
7455
7456
                return setNodeType(self, node, *applied.returnType);
7457
            }
7458
        }
7459
    }
7460
    let case Type::Fn(info) = calleeTy else {
7461
        throw emitError(self, call.callee, ErrorKind::TypeMismatch(TypeMismatch {
7462
            expected: Type::Unknown,
7463
            actual: calleeTy,
7464
        }));
7465
    };
7466
    let applied = try instantiateCall(self, node, call, info);
7467
    try checkCallArgs(self, node, call, applied, ctx);
7468
    // Associate function type to callee.
7469
    setNodeType(self, call.callee, Type::Fn(applied));
7470
7471
    // Associate return type to call.
7472
    return setNodeType(self, node, *applied.returnType);
7473
}
7474
7475
/// Check the allocator layout and the callback ABI used by slice append.
7476
unsafe fn isSliceAllocator(ty: Type) -> bool {
7477
    let case Type::Nominal(NominalType::Record(rec)) = ty else return false;
7478
    if rec.fields.len <> 2 or not rec.labeled {
7479
        return false;
7480
    }
7481
    let func = rec.fields[0];
7482
    let ctx = rec.fields[1];
7483
    let funcName = func.name else return false;
7484
    let ctxName = ctx.name else return false;
7485
    if not mem::eq(funcName, "func") or not mem::eq(ctxName, "ctx") or
7486
       func.offset <> 0 or ctx.offset <> 8
7487
    {
7488
        return false;
7489
    }
7490
    let case Type::Fn(callback) = func.fieldType else return false;
7491
    let case Type::Pointer { target, .. } = ctx.fieldType else return false;
7492
    if *target <> Type::Opaque or callback.paramTypes.len <> 3 or callback.throwList.len <> 0 {
7493
        return false;
7494
    }
7495
    if not typesEqual(*callback.paramTypes[0], ctx.fieldType) or
7496
       *callback.paramTypes[1] <> Type::U32 or *callback.paramTypes[2] <> Type::U32
7497
    {
7498
        return false;
7499
    }
7500
    let case Type::Pointer { class, target: result, mutable } = *callback.returnType
7501
        else return false;
7502
    return class == types::PointerClass::Owned and mutable and *result == Type::Opaque;
7503
}
7504
7505
/// Resolve `slice.append(val, allocator)`.
7506
unsafe fn resolveSliceAppend 'arena (
7507
    self: &mut Resolver 'arena,
7508
    node: *ast::Node,
7509
    parent: *ast::Node,
7510
    parentType: Type,
7511
    args: *[*ast::Node],
7512
    elemType: *Type,
7513
    mutable: bool
7514
) -> Type throws (ResolveError) {
7515
    if not mutable {
7516
        throw emitError(self, parent, ErrorKind::ImmutableBinding);
7517
    }
7518
    if args.len <> 2 {
7519
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
7520
            expected: 2,
7521
            actual: args.len as u32,
7522
        }));
7523
    }
7524
    // First argument must be assignable to the element type.
7525
    try checkAssignable(self, args[0], *elemType);
7526
    // The allocator stores its callback and context at fixed offsets.
7527
    let allocatorTy = try infer(self, args[1]);
7528
    if let case Type::Nominal(info) = allocatorTy {
7529
        try ensureNominalResolved(self, info, args[1]);
7530
    }
7531
    if not isSliceAllocator(allocatorTy) {
7532
        throw emitError(self, args[1], ErrorKind::InvalidSliceAllocator);
7533
    }
7534
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType };
7535
7536
    // Return the parent's type so the caller can rebind:
7537
    return setNodeType(self, node, parentType);
7538
}
7539
7540
/// Resolve `slice.delete(index)`.
7541
unsafe fn resolveSliceDelete 'arena (
7542
    self: &mut Resolver 'arena,
7543
    node: *ast::Node,
7544
    parent: *ast::Node,
7545
    args: *[*ast::Node],
7546
    elemType: *Type,
7547
    mutable: bool
7548
) -> Type throws (ResolveError) {
7549
    if not mutable {
7550
        throw emitError(self, parent, ErrorKind::ImmutableBinding);
7551
    }
7552
    if args.len <> 1 {
7553
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
7554
            expected: 1,
7555
            actual: args.len as u32,
7556
        }));
7557
    }
7558
    try checkAssignable(self, args[0], Type::U32);
7559
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType };
7560
7561
    return setNodeType(self, node, Type::Void);
7562
}
7563
7564
/// Analyze an assignment expression.
7565
unsafe fn resolveAssign 'arena (self: &mut Resolver 'arena, node: *ast::Node, assign: ast::Assign) -> Type
7566
    throws (ResolveError)
7567
{
7568
    // Slice assignment: `slice[range] = value`.
7569
    if let case ast::NodeValue::Subscript { container, index } = assign.left.value {
7570
        if let case ast::NodeValue::Range(range) = index.value {
7571
            try infer(self, index);
7572
            let containerTy = try infer(self, container);
7573
            if not try canMutateThrough(self, container) {
7574
                throw emitError(self, container, ErrorKind::ImmutableBinding);
7575
            }
7576
            let subjectTy = autoDeref(containerTy);
7577
            try checkSliceRangeIndices(self, range);
7578
7579
            let mut item: *Type = undefined;
7580
            let mut capacity: ?u32 = nil;
7581
7582
            if let case Type::Slice { item: sliceItem, mutable: sliceMutable, .. } = subjectTy {
7583
                if not sliceMutable {
7584
                    throw emitError(self, container, ErrorKind::ImmutableBinding);
7585
                }
7586
                set item = sliceItem;
7587
            } else {
7588
                match subjectTy {
7589
                    case Type::Array(a) => {
7590
                        try validateArraySliceBounds(self, range, a.length, node);
7591
                        set item = a.item;
7592
                        set capacity = a.length;
7593
                    }
7594
                    else => throw emitError(self, container, ErrorKind::ExpectedIndexable),
7595
                }
7596
            }
7597
            // RHS is either a fill value or a source slice.
7598
            let rhsTy = try infer(self, assign.right);
7599
            if let case Type::Slice { item: sourceItem, .. } = rhsTy {
7600
                if *sourceItem <> *item {
7601
                    throw emitTypeMismatch(
7602
                        self,
7603
                        assign.right,
7604
                        TypeMismatch { expected: *item, actual: *sourceItem },
7605
                    );
7606
                }
7607
            } else {
7608
                try checkAssignable(self, assign.right, *item);
7609
            }
7610
            try validateRegionalStore(self, assign.left, assign.right, *item);
7611
            setSliceRangeInfo(self, node, SliceRangeInfo { itemType: item, mutable: true, capacity });
7612
            setNodeType(self, assign.left, *item);
7613
7614
            return setNodeType(self, node, Type::Void);
7615
        }
7616
    }
7617
    let leftTy = try infer(self, assign.left);
7618
7619
    if let case ast::NodeValue::Deref(target) = assign.left.value {
7620
        if let case Type::Cell { class, .. } = try infer(self, target) {
7621
            try checkAssignable(self, assign.right, leftTy);
7622
            if let case types::PointerClass::Region(region) = class {
7623
                try validateRegionStorage(self, assign.right, leftTy, region);
7624
            } else if class == types::PointerClass::Owned and containsRegion(leftTy) {
7625
                throw emitError(self, assign.right, ErrorKind::InvalidCellPayload);
7626
            }
7627
            return setNodeType(self, node, leftTy);
7628
        }
7629
    }
7630
7631
    // Check if the left-hand side can be assigned to by checking if it's a mutable location.
7632
    if not try canBorrowMutFrom(self, assign.left) {
7633
        throw emitError(self, assign.left, ErrorKind::ImmutableBinding);
7634
    }
7635
    try checkAssignable(self, assign.right, leftTy);
7636
    try validateRegionalStore(self, assign.left, assign.right, leftTy);
7637
7638
    return setNodeType(self, node, leftTy);
7639
}
7640
7641
/// Ensure slice range bounds are valid `u32` values.
7642
unsafe fn checkSliceRangeIndices 'arena (self: &mut Resolver 'arena, range: ast::Range) throws (ResolveError) {
7643
    if let start = range.start {
7644
        try checkIndex(self, start);
7645
    }
7646
    if let end = range.end {
7647
        try checkIndex(self, end);
7648
    }
7649
}
7650
7651
/// Emit an error when a slice range with compile-tyime values exceeds the array length.
7652
unsafe fn validateArraySliceBounds 'arena (self: &mut Resolver 'arena, range: ast::Range, length: u32, site: *ast::Node) throws (ResolveError) {
7653
    let mut startVal: ?u32 = nil;
7654
    let mut endVal: ?u32 = length;
7655
7656
    if let startNode = range.start {
7657
        if let val = constSliceIndex(self, startNode) {
7658
            set startVal = val;
7659
        }
7660
    }
7661
    if let endNode = range.end {
7662
        if let val = constSliceIndex(self, endNode) {
7663
            set endVal = val;
7664
        }
7665
    }
7666
    if let val = startVal; val > length {
7667
        throw emitError(self, site, ErrorKind::SliceRangeOutOfBounds);
7668
    }
7669
    if let val = endVal; val > length {
7670
        throw emitError(self, site, ErrorKind::SliceRangeOutOfBounds);
7671
    }
7672
    if let start = startVal {
7673
        if let end = endVal; start > end {
7674
            throw emitError(self, site, ErrorKind::SliceRangeOutOfBounds);
7675
        }
7676
    }
7677
}
7678
7679
/// Check that an index expression has an unsigned integer type.
7680
/// Accepts `u8`, `u16`, `u32` and unsuffixed integer literals.
7681
/// Smaller types are widened to `u32` via a numeric cast coercion.
7682
unsafe fn checkIndex 'arena (self: &mut Resolver 'arena, indexNode: *ast::Node) throws (ResolveError) {
7683
    let indexTy = try visit(self, indexNode, Type::U32);
7684
    if indexTy == Type::Int or indexTy == Type::U32 {
7685
        let _ = try expectAssignable(self, Type::U32, indexTy, indexNode);
7686
        return;
7687
    }
7688
    match indexTy {
7689
        case Type::U8, Type::U16 => {
7690
            setNodeCoercion(self, indexNode, Coercion::NumericCast {
7691
                from: indexTy, to: Type::U32,
7692
            });
7693
        }
7694
        else => {
7695
            throw emitTypeMismatch(self, indexNode, TypeMismatch {
7696
                expected: Type::U32,
7697
                actual: indexTy,
7698
            });
7699
        }
7700
    }
7701
}
7702
7703
/// Analyze an array or slice subscript expression.
7704
unsafe fn resolveSubscript 'arena (self: &mut Resolver 'arena, node: *ast::Node, container: *ast::Node, indexNode: *ast::Node) -> Type
7705
    throws (ResolveError)
7706
{
7707
    // Range subscripts always require `&` to form a slice.
7708
    if let case ast::NodeValue::Range(range) = indexNode.value {
7709
        let _ = try infer(self, indexNode);
7710
        let _ = try infer(self, container);
7711
        try checkSliceRangeIndices(self, range);
7712
        throw emitError(self, node, ErrorKind::SliceRequiresAddress);
7713
    }
7714
    let containerTy = try infer(self, container);
7715
    if isUnsafePointerType(containerTy) {
7716
        try requireUnsafe(self, container);
7717
    }
7718
    try checkIndex(self, indexNode);
7719
    let subjectTy = autoDeref(containerTy);
7720
    if let case Type::Slice { item, .. } = subjectTy {
7721
        return setNodeType(self, node, *item);
7722
    }
7723
7724
    match subjectTy {
7725
        case Type::Array(arrayInfo) => {
7726
            return setNodeType(self, node, *arrayInfo.item);
7727
        }
7728
        else => {
7729
            throw emitError(self, container, ErrorKind::ExpectedIndexable);
7730
        }
7731
    }
7732
}
7733
7734
/// Find a record field by name.
7735
fn findRecordField(s: &RecordType, fieldName: *[u8]) -> ?u32 {
7736
    for field, i in s.fields {
7737
        if let name = field.name {
7738
            if name == fieldName {
7739
                return i;
7740
            }
7741
        }
7742
    }
7743
    return nil;
7744
}
7745
7746
/// Analyze a union constructor call with payload.
7747
unsafe fn resolveUnionConstructorCall 'arena (self: &mut Resolver 'arena, node: *ast::Node, call: ast::Call, unionNominal: *unsafe NominalType) -> Type
7748
    throws (ResolveError)
7749
{
7750
    // Get the union nominal type.
7751
    let case NominalType::Union(unionType) = *unionNominal
7752
        else panic "resolveUnionConstructorCall: not a union type";
7753
7754
    // Callee was already visited; get the variant index it set.
7755
    let case NodeExtra::UnionVariant { ordinal: index, tag } = self.nodeData.entries[call.callee.id].extra else {
7756
        throw emitError(self, call.callee, ErrorKind::Internal);
7757
    };
7758
    let variant = &unionType.variants[index];
7759
7760
    // Associate variant index with `call` node for the lowerer.
7761
    setVariantInfo(self, node, index, tag);
7762
7763
    // Check if this variant expects a payload.
7764
    let payloadType = variant.valueType;
7765
    if payloadType <> Type::Void {
7766
        try ensureTypeResolved(self, payloadType, node);
7767
        let recInfo = getRecord(payloadType)
7768
            else panic "resolveUnionVariantConstructor: payload is not a record";
7769
        try checkRecordConstructorArgs(self, node, call.args, recInfo);
7770
    } else {
7771
        if call.args.len > 0 {
7772
            throw emitError(self, node, ErrorKind::UnionVariantPayloadUnexpected(variant.name));
7773
        }
7774
    }
7775
    return setNodeType(self, node, Type::Nominal(unionNominal));
7776
}
7777
7778
/// Analyze an unlabeled record constructor call.
7779
///
7780
/// Handles the syntax `R(a, b)` for unlabeled records, checking that the
7781
/// number of arguments matches the record's field count and that each argument
7782
/// is assignable to its corresponding field type.
7783
unsafe fn resolveRecordConstructorCall 'arena (self: &mut Resolver 'arena, node: *ast::Node, call: ast::Call, recordType: *unsafe NominalType) -> Type
7784
    throws (ResolveError)
7785
{
7786
    let case NominalType::Record(recInfo) = *recordType
7787
        else panic "resolveRecordConstructorCall: not a record type";
7788
7789
    try checkRecordConstructorArgs(self, node, call.args, recInfo);
7790
    return setNodeType(self, node, Type::Nominal(recordType));
7791
}
7792
7793
/// Resolve the type name of a record literal, handling both record types and
7794
/// union variant payloads like `Union::Variant { ... }`.
7795
unsafe fn resolveRecordLitType 'arena (
7796
    self: &mut Resolver 'arena, node: *ast::Node, typeIdent: *ast::Node, hint: Type
7797
) -> ResolvedRecordLitType
7798
    throws (ResolveError)
7799
{
7800
    if let case ast::NodeValue::RegionApply { .. } = typeIdent.value {
7801
        let ty = try infer(self, typeIdent);
7802
        let case Type::Nominal(info) = ty else throw emitError(self, node, ErrorKind::ExpectedRecord);
7803
        return ResolvedRecordLitType { recordType: info, resultType: ty };
7804
    }
7805
    // Check if this is a scope access that might be a union variant.
7806
    if let case ast::NodeValue::ScopeAccess(access) = typeIdent.value {
7807
        let scope = self.scope;
7808
        let sym = try resolveAccess(self, typeIdent, access, scope);
7809
7810
        // Check if resolved symbol is a union variant.
7811
        if let case SymbolData::Variant { type, decl, ordinal, index } = sym.data {
7812
            let sourceTy = typeFor(self, typeIdent) else panic "resolveRecordLitType: missing union type";
7813
            let case Type::Nominal(source) = sourceTy else panic "resolveRecordLitType: invalid union type";
7814
            let unionNominalType = hintedNominal(source, hint);
7815
            try requireNominalArguments(self, unionNominalType, typeIdent);
7816
            try ensureNominalResolved(self, unionNominalType, typeIdent);
7817
            let case NominalType::Union(body) = *unionNominalType else panic;
7818
            let case Type::Nominal(payloadInfo) = body.variants[ordinal].valueType
7819
                else throw emitError(self, node, ErrorKind::ExpectedRecord);
7820
7821
            // Store the variant index for the lowerer.
7822
            setVariantInfo(self, node, ordinal, index);
7823
7824
            return ResolvedRecordLitType {
7825
                recordType: payloadInfo,
7826
                resultType: Type::Nominal(unionNominalType),
7827
            };
7828
        }
7829
        // Not a variant, must be a type.
7830
        let case SymbolData::Type(ty) = sym.data
7831
            else throw emitError(self, node, ErrorKind::ExpectedRecord);
7832
        return ResolvedRecordLitType {
7833
            recordType: ty,
7834
            resultType: Type::Nominal(ty),
7835
        };
7836
    }
7837
    // Simple identifier, resolve as type name.
7838
    let tyInfo = try resolveTypeName(self, typeIdent);
7839
    return ResolvedRecordLitType {
7840
        recordType: tyInfo,
7841
        resultType: Type::Nominal(tyInfo),
7842
    };
7843
}
7844
7845
/// Analyze a record literal expression.
7846
unsafe fn resolveRecordLit 'arena (self: &mut Resolver 'arena, node: *ast::Node, lit: ast::RecordLit, hint: Type) -> Type
7847
    throws (ResolveError)
7848
{
7849
    // If no type name, infer an anonymous tuple type.
7850
    let typeIdent = lit.typeName else {
7851
        return try resolveAnonRecordLit(self, node, lit, hint);
7852
    };
7853
    // Resolve the type name, handling both record types and union variants.
7854
    let resolved = try resolveRecordLitType(self, node, typeIdent, hint);
7855
    let mut tyInfo = resolved.recordType;
7856
    let mut resultType = resolved.resultType;
7857
    let mut target = hint;
7858
    if let case Type::Optional(inner) = target {
7859
        set target = *inner;
7860
    }
7861
    if nominalApplication(tyInfo) == nil {
7862
        if let case Type::Nominal(info) = target {
7863
            if let applied = nominalApplication(info); applied.base == tyInfo {
7864
                set tyInfo = info;
7865
                set resultType = target;
7866
            }
7867
        }
7868
    }
7869
    try requireNominalArguments(self, tyInfo, typeIdent);
7870
7871
    // Lazily resolve record body if not yet done.
7872
    try ensureNominalResolved(self, tyInfo, typeIdent);
7873
    let case NominalType::Record(recordType) = *tyInfo
7874
        else throw emitError(self, node, ErrorKind::ExpectedRecord);
7875
7876
    // Unlabeled records must use constructor call syntax `R(...)`, not brace syntax.
7877
    if not recordType.labeled {
7878
        throw emitError(self, node, ErrorKind::RecordFieldStyleMismatch);
7879
    }
7880
    // Check field count. With `{ .. }` syntax, fewer fields are allowed.
7881
    if lit.fields.len > recordType.fields.len {
7882
        throw emitError(self, node, ErrorKind::RecordFieldCountMismatch(CountMismatch {
7883
            expected: recordType.fields.len as u32,
7884
            actual: lit.fields.len,
7885
        }));
7886
    }
7887
    if not lit.ignoreRest and lit.fields.len < recordType.fields.len {
7888
        let missingName = recordType.fields[lit.fields.len].name else panic;
7889
        throw emitError(self, node, ErrorKind::RecordFieldMissing(missingName));
7890
    }
7891
7892
    // Fields must be in declaration order.
7893
    for fieldNode, idx in lit.fields {
7894
        let case ast::NodeValue::RecordLitField(fieldArg) = fieldNode.value
7895
            else panic "resolveRecordLit: expected field node value";
7896
        let label = fieldArg.label
7897
            else panic "resolveRecordLit: expected labeled field";
7898
        let fieldName = try nodeName(self, label);
7899
        let expected = recordType.fields[idx];
7900
        let expectedName = expected.name else panic;
7901
7902
        if fieldName <> expectedName {
7903
            throw emitError(self, fieldNode, ErrorKind::RecordFieldOutOfOrder {
7904
                field: fieldName,
7905
                prev: expectedName,
7906
            });
7907
        }
7908
        setRecordFieldIndex(self, fieldNode, idx);
7909
        try checkAssignable(self, fieldArg.value, expected.fieldType);
7910
        setNodeType(self, fieldNode, expected.fieldType);
7911
    }
7912
    return setNodeType(self, node, resultType);
7913
}
7914
7915
/// Analyze an anonymous record literal, checking fields against the hint type.
7916
unsafe fn resolveAnonRecordLit 'arena (self: &mut Resolver 'arena, node: *ast::Node, lit: ast::RecordLit, hint: Type) -> Type
7917
    throws (ResolveError)
7918
{
7919
    // Unwrap optional hint to get the inner record type.
7920
    let mut innerHint = hint;
7921
    if let case Type::Optional(inner) = hint {
7922
        set innerHint = *inner;
7923
    }
7924
    let mut hintInfo: ?RecordType = nil;
7925
    if let case Type::Nominal(info) = innerHint {
7926
        try ensureNominalResolved(self, info, node);
7927
        if let case NominalType::Record(s) = *info {
7928
            set hintInfo = s;
7929
        }
7930
    }
7931
    let targetInfo = hintInfo else {
7932
        throw emitError(self, node, ErrorKind::CannotInferType);
7933
    };
7934
7935
    // Check field count.
7936
    if lit.fields.len <> targetInfo.fields.len {
7937
        if lit.fields.len < targetInfo.fields.len {
7938
            let missingName = targetInfo.fields[lit.fields.len].name else panic;
7939
            throw emitError(self, node, ErrorKind::RecordFieldMissing(missingName));
7940
        } else {
7941
            throw emitError(self, node, ErrorKind::RecordFieldCountMismatch(CountMismatch {
7942
                expected: targetInfo.fields.len as u32,
7943
                actual: lit.fields.len,
7944
            }));
7945
        }
7946
    }
7947
7948
    // Fields must be in declaration order.
7949
    for fieldNode, idx in lit.fields {
7950
        let case ast::NodeValue::RecordLitField(fieldArg) = fieldNode.value
7951
            else panic "resolveAnonRecordLit: expected field node value";
7952
        let label = fieldArg.label
7953
            else panic "resolveAnonRecordLit: expected labeled field";
7954
        let fieldName = try nodeName(self, label);
7955
        let expected = targetInfo.fields[idx];
7956
        let expectedName = expected.name else panic;
7957
7958
        if fieldName <> expectedName {
7959
            throw emitError(self, fieldNode, ErrorKind::RecordFieldOutOfOrder {
7960
                field: fieldName,
7961
                prev: expectedName,
7962
            });
7963
        }
7964
        setRecordFieldIndex(self, fieldNode, idx);
7965
        let fieldType = try visit(self, fieldArg.value, expected.fieldType);
7966
7967
        try expectAssignable(self, expected.fieldType, fieldType, fieldArg.value);
7968
        setNodeType(self, fieldNode, fieldType);
7969
    }
7970
    return setNodeType(self, node, innerHint);
7971
}
7972
7973
/// Analyze an array literal expression.
7974
unsafe fn resolveArrayLit 'arena (self: &mut Resolver 'arena, node: *ast::Node, items: *[*ast::Node], hint: Type) -> Type
7975
    throws (ResolveError)
7976
{
7977
    let length = items.len;
7978
    let mut expectedTy: Type = Type::Unknown;
7979
7980
    if let case Type::Array(ary) = hint {
7981
        set expectedTy = *ary.item;
7982
    } else if let case Type::Optional(inner) = hint {
7983
        if let case Type::Array(ary) = *inner {
7984
            set expectedTy = *ary.item;
7985
        }
7986
    };
7987
    for itemNode in items {
7988
        let itemTy = try visit(self, itemNode, expectedTy);
7989
        assert itemTy <> Type::Unknown;
7990
7991
        // Set the expected type to the first type we encounter.
7992
        if expectedTy == Type::Unknown {
7993
            set expectedTy = itemTy;
7994
        } else {
7995
            try expectAssignable(self, expectedTy, itemTy, itemNode);
7996
        }
7997
    }
7998
    if expectedTy == Type::Unknown {
7999
        throw emitError(self, node, ErrorKind::CannotInferType);
8000
    };
8001
    let arrayTy = Type::Array(ArrayType { item: allocType(self, expectedTy), length });
8002
    return setNodeType(self, node, arrayTy);
8003
}
8004
8005
/// Analyze an array repeat literal expression.
8006
unsafe fn resolveArrayRepeat 'arena (self: &mut Resolver 'arena, node: *ast::Node, lit: ast::ArrayRepeatLit, hint: Type) -> Type
8007
    throws (ResolveError)
8008
{
8009
    let mut itemHint = hint;
8010
    if let case Type::Array(ary) = hint {
8011
        set itemHint = *ary.item;
8012
    } else if let case Type::Optional(inner) = hint {
8013
        if let case Type::Array(ary) = *inner {
8014
            set itemHint = *ary.item;
8015
        }
8016
    }
8017
    let valueTy = try visit(self, lit.item, itemHint);
8018
    let count = try checkSizeInt(self, lit.count);
8019
    let arrayTy = Type::Array(ArrayType {
8020
        item: allocType(self, valueTy),
8021
        length: count,
8022
    });
8023
    return setNodeType(self, node, arrayTy);
8024
}
8025
8026
/// Resolve union variant access.
8027
unsafe fn resolveUnionVariantAccess 'arena (
8028
    self: &mut Resolver 'arena,
8029
    node: *ast::Node,
8030
    access: ast::Access,
8031
    unionType: UnionType,
8032
    variantName: *[u8]
8033
) -> *unsafe mut Symbol throws (ResolveError) {
8034
    // Look up the variant in the union's nominal type.
8035
    for i in 0..unionType.variants.len {
8036
        let variant = &unionType.variants[i];
8037
        if variant.name == variantName {
8038
            let case SymbolData::Variant { ordinal, index, .. } = variant.symbol.data
8039
                else panic "resolveUnionVariantAccess: expected variant symbol";
8040
8041
            // Associate the variant symbol with the child node.
8042
            setNodeSymbol(self, access.child, variant.symbol);
8043
            setNodeSymbol(self, node, variant.symbol);
8044
8045
            // Store the variant index for the lowerer.
8046
            setVariantInfo(self, node, ordinal, index);
8047
8048
            return variant.symbol;
8049
        }
8050
    }
8051
    throw emitError(self, access.child, ErrorKind::UnresolvedSymbol(variantName));
8052
}
8053
8054
/// Analyze a scope access expression.
8055
unsafe fn resolveScopeAccess 'arena (self: &mut Resolver 'arena, node: *ast::Node, access: ast::Access, hint: Type) -> Type
8056
    throws (ResolveError)
8057
{
8058
    let scope = self.scope;
8059
    let sym = try resolveAccess(self, node, access, scope);
8060
    try checkStaticAccess(self, node, sym);
8061
    let mut ty: Type = undefined;
8062
8063
    match sym.data {
8064
        case SymbolData::Value { type, .. } => {
8065
            setNodeSymbol(self, node, sym);
8066
            set ty = type;
8067
        }
8068
        case SymbolData::Constant { type, value } => {
8069
            // Propagate the constant value.
8070
            if let val = value {
8071
                setNodeConstValue(self, node, val);
8072
            }
8073
            setNodeSymbol(self, node, sym);
8074
            set ty = type;
8075
        }
8076
        case SymbolData::Type(t) => {
8077
            setNodeSymbol(self, node, sym);
8078
            set ty = Type::Nominal(hintedNominal(t, hint));
8079
        }
8080
        case SymbolData::Variant { index, .. } => {
8081
            let ty = typeFor(self, node)
8082
                else throw emitError(self, node, ErrorKind::Internal);
8083
            let case Type::Nominal(info) = ty else panic "resolveScopeAccess: invalid variant type";
8084
            let applied = hintedNominal(info, hint);
8085
            try requireNominalArguments(self, applied, node);
8086
            try ensureNominalResolved(self, applied, node);
8087
            let variantTy = Type::Nominal(applied);
8088
            // For unions without payload, store the variant index as a constant.
8089
            if isVoidUnion(variantTy) {
8090
                setNodeConstValue(self, node, ConstValue::Int(ConstInt {
8091
                    magnitude: index as u64,
8092
                    bits: 32,
8093
                    signed: false,
8094
                    negative: false,
8095
                }));
8096
            }
8097
            return setNodeType(self, node, variantTy);
8098
        }
8099
        case SymbolData::Module { .. } => {
8100
            throw emitError(self, node, ErrorKind::UnexpectedModuleName);
8101
        }
8102
        case SymbolData::Trait(_) => { // Trait names are not values.
8103
            throw emitError(self, node, ErrorKind::UnexpectedTraitName);
8104
        }
8105
    }
8106
    return setNodeType(self, node, ty);
8107
}
8108
8109
/// Analyze a field access expression.
8110
unsafe fn resolveFieldAccess 'arena (self: &mut Resolver 'arena, node: *ast::Node, access: ast::Access) -> Type
8111
    throws (ResolveError)
8112
{
8113
    let parentTy = try infer(self, access.parent);
8114
    if isUnsafePointerType(parentTy) {
8115
        try requireUnsafe(self, access.parent);
8116
    }
8117
    let subjectTy = autoDeref(parentTy);
8118
    try ensureTypeResolved(self, subjectTy, access.parent);
8119
8120
    if let case Type::Slice { class, item, mutable } = subjectTy {
8121
        let fieldNode = access.child;
8122
        let fieldName = try nodeName(self, fieldNode);
8123
        if mem::eq(fieldName, PTR_FIELD) {
8124
            try requireUnsafe(self, node);
8125
            setRecordFieldIndex(self, fieldNode, 0);
8126
            return setNodeType(
8127
                self,
8128
                node,
8129
                Type::Pointer { class, target: item, mutable },
8130
            );
8131
        }
8132
        if mem::eq(fieldName, LEN_FIELD) {
8133
            setRecordFieldIndex(self, fieldNode, 1);
8134
            return setNodeType(self, node, Type::U32);
8135
        }
8136
        if mem::eq(fieldName, CAP_FIELD) {
8137
            setRecordFieldIndex(self, fieldNode, 2);
8138
            return setNodeType(self, node, Type::U32);
8139
        }
8140
        throw emitError(self, node, ErrorKind::SliceFieldUnknown(fieldName));
8141
    }
8142
    if let case Type::TraitObject { traitInfo, .. } = subjectTy {
8143
        let fieldName = try nodeName(self, access.child);
8144
        let method = findTraitMethod(traitInfo, fieldName)
8145
            else throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
8146
        return setNodeType(self, node, Type::Fn(method.fnType));
8147
    }
8148
8149
    match subjectTy {
8150
        case Type::Nominal(NominalType::Record(recordType)) => {
8151
            let fieldNode = access.child;
8152
            let fieldName = try nodeName(self, fieldNode);
8153
            if let fieldIndex = findRecordField(&recordType, fieldName) {
8154
                let fieldTy = recordType.fields[fieldIndex].fieldType;
8155
                setRecordFieldIndex(self, fieldNode, fieldIndex);
8156
                return setNodeType(self, node, fieldTy);
8157
            }
8158
            // Not a field: check for a standalone method.
8159
            if let method = findMethod(self, subjectTy, fieldName) {
8160
                return setNodeType(self, node, Type::Fn(method.fnType));
8161
            }
8162
            throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
8163
        }
8164
        case Type::Array(arrayInfo) => {
8165
            let fieldNode = access.child;
8166
            let fieldName = try nodeName(self, fieldNode);
8167
8168
            if mem::eq(fieldName, LEN_FIELD) {
8169
                let lengthConst = constInt(arrayInfo.length as u64, 32, false, false);
8170
                setNodeConstValue(self, node, lengthConst);
8171
8172
                return setNodeType(self, node, Type::U32);
8173
            }
8174
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
8175
        }
8176
8177
        else => {
8178
            // Check for standalone methods on any nominal type (e.g. unions).
8179
            if let case Type::Nominal(_) = subjectTy {
8180
                let fieldName = try nodeName(self, access.child);
8181
                if let method = findMethod(self, subjectTy, fieldName) {
8182
                    return setNodeType(self, node, Type::Fn(method.fnType));
8183
                }
8184
            }
8185
            throw emitError(self, access.parent, ErrorKind::ExpectedRecord);
8186
        }
8187
    }
8188
}
8189
8190
/// Return whether a pointer-like value grants mutable access.
8191
fn isMutablePointerLike(ty: Type) -> bool {
8192
    match ty {
8193
        case Type::Pointer { mutable, .. } => return mutable,
8194
        case Type::Slice { mutable, .. } => return mutable,
8195
        case Type::TraitObject { mutable, .. } => return mutable,
8196
        else => return false,
8197
    }
8198
}
8199
8200
/// Check exclusive access to an element or field of a container.
8201
unsafe fn canAccessExclusiveProjection 'arena (self: &mut Resolver 'arena, container: *ast::Node) -> bool
8202
    throws (ResolveError)
8203
{
8204
    let ty = try infer(self, container);
8205
    if let case Type::Slice { mutable: false, .. } = autoDeref(ty) {
8206
        return false;
8207
    }
8208
    match ty {
8209
        case Type::Pointer { class, mutable, .. } => {
8210
            if not mutable {
8211
                return false;
8212
            }
8213
            if class == types::PointerClass::Unsafe {
8214
                return true;
8215
            }
8216
        }
8217
        case Type::Slice { class, mutable, .. } => {
8218
            if not mutable {
8219
                return false;
8220
            }
8221
            if class == types::PointerClass::Unsafe {
8222
                return true;
8223
            }
8224
        }
8225
        else => {
8226
        },
8227
    }
8228
    return try canAccessExclusiveHandle(self, container);
8229
}
8230
8231
/// Check that a stored exclusive handle is not reached through shared access.
8232
unsafe fn canAccessExclusiveHandle 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> bool
8233
    throws (ResolveError)
8234
{
8235
    match node.value {
8236
        case ast::NodeValue::FieldAccess(access) =>
8237
            return try canAccessExclusiveProjection(self, access.parent),
8238
        case ast::NodeValue::Subscript { container, .. } =>
8239
            return try canAccessExclusiveProjection(self, container),
8240
        case ast::NodeValue::Deref(inner) =>
8241
            return try canAccessExclusiveProjection(self, inner),
8242
        case ast::NodeValue::As(expr) =>
8243
            return try canAccessExclusiveHandle(self, expr.value),
8244
        case ast::NodeValue::CondExpr(cond) => {
8245
            if not try canAccessExclusiveHandle(self, cond.thenExpr) {
8246
                return false;
8247
            }
8248
            return try canAccessExclusiveHandle(self, cond.elseExpr);
8249
        }
8250
        else => return true,
8251
    }
8252
}
8253
8254
/// Check target mutability for implicit pointer access.
8255
unsafe fn canMutateThrough 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> bool
8256
    throws (ResolveError)
8257
{
8258
    let ty = try infer(self, node);
8259
    match ty {
8260
        case Type::Pointer { class, mutable, .. } => {
8261
            if not mutable {
8262
                return false;
8263
            }
8264
            if class == types::PointerClass::Unsafe {
8265
                return true;
8266
            }
8267
            return try canAccessExclusiveHandle(self, node);
8268
        }
8269
        case Type::Slice { class, mutable, .. } => {
8270
            if not mutable {
8271
                return false;
8272
            }
8273
            if class == types::PointerClass::Unsafe {
8274
                return true;
8275
            }
8276
            return try canAccessExclusiveHandle(self, node);
8277
        }
8278
        case Type::TraitObject { class, mutable, .. } => {
8279
            if not mutable {
8280
                return false;
8281
            }
8282
            if class == types::PointerClass::Unsafe {
8283
                return true;
8284
            }
8285
            return try canAccessExclusiveHandle(self, node);
8286
        }
8287
        else => return try canBorrowMutFrom(self, node),
8288
    }
8289
}
8290
8291
/// Determine whether an expression can yield a mutable location for borrowing.
8292
unsafe fn canBorrowMutFrom 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> bool
8293
    throws (ResolveError)
8294
{
8295
    match node.value {
8296
        case ast::NodeValue::Ident(name) => {
8297
            let sym = findValueSymbol(self.scope, name)
8298
                else return false;
8299
            let case SymbolData::Value { mutable, .. } = sym.data
8300
                else return false;
8301
            return mutable;
8302
        }
8303
        case ast::NodeValue::FieldAccess(access) => {
8304
            let parentTy = try infer(self, access.parent);
8305
            if let case Type::Slice { .. } = autoDeref(parentTy) {
8306
                try requireUnsafe(self, node);
8307
            }
8308
            return try canMutateThrough(self, access.parent);
8309
        }
8310
        case ast::NodeValue::ScopeAccess(_) => {
8311
            // Module-qualified access to a top-level symbol. A `static`
8312
            // binds as a mutable value; a `constant` does not.
8313
            let _ = try infer(self, node);
8314
            let sym = nodeData(self, node).sym
8315
                else return false;
8316
8317
            if let case SymbolData::Value { mutable, .. } = sym.data {
8318
                return mutable;
8319
            }
8320
            return false;
8321
        }
8322
        case ast::NodeValue::Subscript { container, .. } => {
8323
            let containerTy = try infer(self, container);
8324
            // Subscript auto-derefs pointers, so check the actual indexed type.
8325
            let subjectTy = autoDeref(containerTy);
8326
8327
            if let case Type::Slice { mutable, .. } = subjectTy {
8328
                if not mutable {
8329
                    return false;
8330
                }
8331
                return try canMutateThrough(self, container);
8332
            }
8333
            if let case Type::Array(_) = subjectTy {
8334
                return try canMutateThrough(self, container);
8335
            }
8336
            return false;
8337
        }
8338
        case ast::NodeValue::ArrayLit(_),
8339
             ast::NodeValue::ArrayRepeatLit(_) =>
8340
        {
8341
            return true;
8342
        }
8343
        case ast::NodeValue::Call(_) => {
8344
            // A call returning `*mut T` (or `&mut [T]`) yields a
8345
            // mutable place. Non-pointer returns cannot be mutably borrowed.
8346
            let ty = try infer(self, node);
8347
            if let case Type::Pointer { mutable, .. } = ty {
8348
                return mutable;
8349
            }
8350
            if let case Type::Slice { mutable, .. } = ty {
8351
                return mutable;
8352
            }
8353
            return false;
8354
        }
8355
        case ast::NodeValue::Deref(inner) => {
8356
            let innerTy = try infer(self, inner);
8357
8358
            if let case Type::Pointer { .. } = innerTy {
8359
                return try canMutateThrough(self, inner);
8360
            }
8361
            if let case Type::Slice { .. } = innerTy {
8362
                return try canMutateThrough(self, inner);
8363
            }
8364
            // Record deref: mutability depends on the inner binding.
8365
            if let case Type::Nominal(NominalType::Record(recInfo)) = innerTy {
8366
                if not recInfo.labeled and recInfo.fields.len == 1 {
8367
                    return try canBorrowMutFrom(self, inner);
8368
                }
8369
            }
8370
            return false;
8371
        }
8372
        else => {
8373
            return false;
8374
        }
8375
    }
8376
}
8377
8378
/// Restrict a pointee lifetime to the borrow of its exclusive owner.
8379
unsafe fn constrainAddressClass(storage: types::PointerClass, owner: types::PointerClass) -> types::PointerClass {
8380
    if owner == types::PointerClass::Owned or owner == types::PointerClass::Unsafe {
8381
        return storage;
8382
    }
8383
    if owner == types::PointerClass::Ref {
8384
        return owner;
8385
    }
8386
    let case types::PointerClass::Region(ownerRegion) = owner else panic;
8387
    if let case types::PointerClass::Region(storageRegion) = storage {
8388
        if types::regionContains(storageRegion, ownerRegion) {
8389
            return owner;
8390
        }
8391
        if types::regionContains(ownerRegion, storageRegion) {
8392
            return storage;
8393
        }
8394
        return types::PointerClass::Ref;
8395
    }
8396
    if storage == types::PointerClass::Owned {
8397
        return owner;
8398
    }
8399
    return storage;
8400
}
8401
8402
/// Get the usable pointee lifetime of a pointer or slice value.
8403
unsafe fn pointerAddressClass 'arena (
8404
    self: &Resolver 'arena, node: *ast::Node, class: types::PointerClass, mutable: bool
8405
) -> types::PointerClass {
8406
    if not mutable or class == types::PointerClass::Unsafe {
8407
        return class;
8408
    }
8409
    return constrainAddressClass(class, exclusiveOwnerClass(self, node));
8410
}
8411
8412
/// Get the lifetime of storage selected by a pointer or slice subscript.
8413
unsafe fn indexedPointerClass 'arena (self: &Resolver 'arena, container: *ast::Node) -> ?types::PointerClass {
8414
    let ty = typeFor(self, container) else return nil;
8415
    if let case Type::Pointer { class, target, mutable } = ty {
8416
        let parentClass = pointerAddressClass(self, container, class, mutable);
8417
        if let case Type::Slice { class: sliceClass, mutable: sliceMutable, .. } = *target {
8418
            if not sliceMutable or sliceClass == types::PointerClass::Unsafe {
8419
                return sliceClass;
8420
            }
8421
            return constrainAddressClass(sliceClass, parentClass);
8422
        }
8423
        return parentClass;
8424
    }
8425
    if let case Type::Slice { class, mutable, .. } = ty {
8426
        return pointerAddressClass(self, container, class, mutable);
8427
    }
8428
    return nil;
8429
}
8430
8431
/// Get the borrow that controls access to a stored exclusive handle.
8432
/// Directly owned values have no additional borrow restriction.
8433
unsafe fn exclusiveOwnerClass 'arena (self: &Resolver 'arena, node: *ast::Node) -> types::PointerClass {
8434
    match node.value {
8435
        case ast::NodeValue::FieldAccess(access) => {
8436
            if let ty = typeFor(self, access.parent) {
8437
                match ty {
8438
                    case Type::Pointer { class, mutable, .. } =>
8439
                        return pointerAddressClass(self, access.parent, class, mutable),
8440
                    case Type::Slice { class, mutable, .. } =>
8441
                        return pointerAddressClass(self, access.parent, class, mutable),
8442
                    else => {
8443
                    },
8444
                }
8445
            }
8446
            return exclusiveOwnerClass(self, access.parent);
8447
        }
8448
        case ast::NodeValue::Subscript { container, .. } => {
8449
            if let class = indexedPointerClass(self, container) {
8450
                return class;
8451
            }
8452
            return exclusiveOwnerClass(self, container);
8453
        }
8454
        case ast::NodeValue::Deref(target) => {
8455
            if let ty = typeFor(self, target) {
8456
                if let case Type::Pointer { class, mutable, .. } = ty {
8457
                    return pointerAddressClass(self, target, class, mutable);
8458
                }
8459
            }
8460
            return exclusiveOwnerClass(self, target);
8461
        }
8462
        case ast::NodeValue::As(expr) => return exclusiveOwnerClass(self, expr.value),
8463
        case ast::NodeValue::CondExpr(cond) =>
8464
            return constrainAddressClass(exclusiveOwnerClass(self, cond.thenExpr), exclusiveOwnerClass(self, cond.elseExpr)),
8465
        else => return types::PointerClass::Owned,
8466
    }
8467
}
8468
8469
/// Return the storage class of an addressed location.
8470
unsafe fn addressStorageClass 'arena (self: &Resolver 'arena, node: *ast::Node) -> types::PointerClass {
8471
    match node.value {
8472
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) => {
8473
            if let sym = symbolFor(self, node) {
8474
                match sym.node.value {
8475
                    case ast::NodeValue::StaticDecl(_), ast::NodeValue::ConstDecl(_) =>
8476
                        return types::PointerClass::Owned,
8477
                    else => {}
8478
                }
8479
            }
8480
        }
8481
        case ast::NodeValue::FieldAccess(access) => {
8482
            if let ty = typeFor(self, access.parent) {
8483
                if let case Type::Pointer { class, mutable, .. } = ty {
8484
                    return pointerAddressClass(self, access.parent, class, mutable);
8485
                }
8486
            }
8487
            return addressStorageClass(self, access.parent);
8488
        }
8489
        case ast::NodeValue::Subscript { container, .. } => {
8490
            if let class = indexedPointerClass(self, container) {
8491
                return class;
8492
            }
8493
            return addressStorageClass(self, container);
8494
        }
8495
        case ast::NodeValue::Deref(target) => {
8496
            if let ty = typeFor(self, target) {
8497
                if let case Type::Pointer { class, mutable, .. } = ty {
8498
                    return pointerAddressClass(self, target, class, mutable);
8499
                }
8500
            }
8501
            return addressStorageClass(self, target);
8502
        }
8503
        else => {}
8504
    }
8505
    return types::PointerClass::Ref;
8506
}
8507
8508
/// Select an address type without extending the target storage lifetime.
8509
unsafe fn addressClass 'arena (self: &mut Resolver 'arena, target: *ast::Node, hint: Type) -> types::PointerClass
8510
    throws (ResolveError)
8511
{
8512
    if isUnsafePointerType(hint) {
8513
        try requireUnsafe(self, target);
8514
        return types::PointerClass::Unsafe;
8515
    }
8516
    if isRefType(hint) {
8517
        if referenceRegion(hint) <> nil {
8518
            return addressStorageClass(self, target);
8519
        }
8520
        return types::PointerClass::Ref;
8521
    }
8522
    match target.value {
8523
        case ast::NodeValue::ArrayLit(_), ast::NodeValue::ArrayRepeatLit(_) => {
8524
            if isConstExpr(self, target) {
8525
                return types::PointerClass::Owned;
8526
            }
8527
        }
8528
        else => {}
8529
    }
8530
    return addressStorageClass(self, target);
8531
}
8532
8533
/// Return whether a place projects into a cell payload snapshot.
8534
unsafe fn isCellPayloadPlace 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> bool
8535
    throws (ResolveError)
8536
{
8537
    match node.value {
8538
        case ast::NodeValue::Deref(target) => {
8539
            if let case Type::Cell { .. } = try infer(self, target) {
8540
                return true;
8541
            }
8542
        }
8543
        case ast::NodeValue::FieldAccess(access) => return try isCellPayloadPlace(self, access.parent),
8544
        case ast::NodeValue::Subscript { container, .. } => return try isCellPayloadPlace(self, container),
8545
        else => {}
8546
    }
8547
    return false;
8548
}
8549
8550
/// Return whether a typed expression accesses a whole cell payload.
8551
export unsafe fn isCellDeref 'arena (self: &Resolver 'arena, node: *ast::Node) -> bool {
8552
    if let case ast::NodeValue::Deref(target) = node.value {
8553
        if let ty = typeFor(self, target) {
8554
            if let case Type::Cell { .. } = ty {
8555
                return true;
8556
            }
8557
        }
8558
    }
8559
    return false;
8560
}
8561
8562
/// Return whether an expression creates shared mutable access to a source place.
8563
fn createsCellBorrow(node: *ast::Node) -> bool {
8564
    match node.value {
8565
        case ast::NodeValue::AddressOf(address) => return address.kind == ast::AddressKind::Cell,
8566
        case ast::NodeValue::As(expr) => return createsCellBorrow(expr.value),
8567
        case ast::NodeValue::RegionApply { value, .. } => return createsCellBorrow(value),
8568
        else => return false,
8569
    }
8570
}
8571
8572
/// Find the exclusive handle that owns an addressed place.
8573
unsafe fn addressOwner 'arena (self: &Resolver 'arena, node: *ast::Node) -> ?*ast::Node {
8574
    let mut parent: *ast::Node = undefined;
8575
    match node.value {
8576
        case ast::NodeValue::Deref(target) => set parent = target,
8577
        case ast::NodeValue::FieldAccess(access) => set parent = access.parent,
8578
        case ast::NodeValue::Subscript { container, .. } => set parent = container,
8579
        else => return nil,
8580
    }
8581
    if let ty = typeFor(self, parent) {
8582
        match ty {
8583
            case Type::Pointer { mutable: true, .. }, Type::Slice { mutable: true, .. } => return parent,
8584
            else => {}
8585
        }
8586
    }
8587
    return addressOwner(self, parent);
8588
}
8589
8590
/// Analyze an address-of expression.
8591
unsafe fn resolveAddressOf 'arena (self: &mut Resolver 'arena, node: *ast::Node, addr: ast::AddressOf, hint: Type) -> Type
8592
    throws (ResolveError)
8593
{
8594
    if try isCellPayloadPlace(self, addr.target) {
8595
        throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
8596
    }
8597
    if addr.kind == ast::AddressKind::Cell and not ast::isPlaceExpr(addr.target) {
8598
        throw emitError(self, addr.target, ErrorKind::RefBinding);
8599
    }
8600
    if ast::isExclusiveAddress(addr) {
8601
        if not try canBorrowMutFrom(self, addr.target) {
8602
            throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
8603
        }
8604
    }
8605
    if let case ast::NodeValue::Subscript { container, index } = addr.target.value {
8606
        if let case ast::NodeValue::Range(range) = index.value {
8607
            if addr.kind == ast::AddressKind::Cell {
8608
                throw emitError(self, addr.target, ErrorKind::InvalidCellPayload);
8609
            }
8610
            let containerTy = try infer(self, container);
8611
            let subjectTy = autoDeref(containerTy);
8612
8613
            try checkSliceRangeIndices(self, range);
8614
8615
            let mut item: *Type = undefined;
8616
            let mut capacity: ?u32 = nil;
8617
8618
            if let case Type::Slice { item: sliceItem, mutable: sliceMutable, .. } = subjectTy {
8619
                if ast::isExclusiveAddress(addr) and not sliceMutable {
8620
                    throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
8621
                }
8622
                set item = sliceItem;
8623
            } else {
8624
                match subjectTy {
8625
                    case Type::Array(arrayInfo) => {
8626
                        try validateArraySliceBounds(self, range, arrayInfo.length, node);
8627
                        set item = arrayInfo.item;
8628
                        set capacity = arrayInfo.length;
8629
                    }
8630
                    else => {
8631
                        throw emitError(self, container, ErrorKind::ExpectedIndexable);
8632
                    }
8633
                }
8634
            }
8635
            let class = try addressClass(self, addr.target, hint);
8636
            let sliceTy = Type::Slice { class, item, mutable: addr.kind == ast::AddressKind::Mutable };
8637
            let alloc = allocType(self, sliceTy);
8638
            setSliceRangeInfo(self, node, SliceRangeInfo {
8639
                itemType: item,
8640
                mutable: addr.kind == ast::AddressKind::Mutable,
8641
                capacity,
8642
            });
8643
            setNodeType(self, addr.target, *alloc);
8644
            return setNodeType(self, node, *alloc);
8645
        }
8646
    }
8647
    // Derive a hint for the target type from the slice hint.
8648
    let mut targetHint: Type = Type::Unknown;
8649
    if let case Type::Slice { item, .. } = hint {
8650
        set targetHint = Type::Array(ArrayType { item, length: 0 });
8651
    }
8652
    let targetTy = try visit(self, addr.target, targetHint);
8653
    let class = try addressClass(self, addr.target, hint);
8654
8655
    // Mark local variable symbols as address-taken so the lowerer
8656
    // allocates a stack slot eagerly.
8657
    if let case ast::NodeValue::Ident(name) = addr.target.value {
8658
        if let sym = findValueSymbol(self.scope, name) {
8659
            match &mut sym.data {
8660
                case SymbolData::Value { addressTaken, .. } => {
8661
                    set *addressTaken = true;
8662
                }
8663
                else => {}
8664
            }
8665
        }
8666
    }
8667
8668
    if addr.kind == ast::AddressKind::Cell {
8669
        try validateCellPayload(self, node, targetTy);
8670
        if let case types::PointerClass::Region(region) = class {
8671
            try validateRegionStorage(self, addr.target, targetTy, region);
8672
        } else if class == types::PointerClass::Owned and containsRegion(targetTy) {
8673
            throw emitError(self, addr.target, ErrorKind::InvalidCellPayload);
8674
        }
8675
        return setNodeType(self, node, Type::Cell { class, payload: allocType(self, targetTy) });
8676
    }
8677
    if let case Type::Array(arrayInfo) = targetTy {
8678
        match addr.target.value {
8679
            case ast::NodeValue::ArrayLit(_),
8680
                 ast::NodeValue::ArrayRepeatLit(_) =>
8681
            {
8682
                let sliceTy = Type::Slice { class, item: arrayInfo.item, mutable: addr.kind == ast::AddressKind::Mutable };
8683
                return setNodeType(self, node, *allocType(self, sliceTy));
8684
            }
8685
            else => {}
8686
        }
8687
    }
8688
    let pointerTy = Type::Pointer {
8689
        class, target: allocType(self, targetTy), mutable: addr.kind == ast::AddressKind::Mutable,
8690
    };
8691
    return setNodeType(self, node, pointerTy);
8692
}
8693
8694
/// Analyze a dereference expression.
8695
unsafe fn resolveDeref 'arena (self: &mut Resolver 'arena, node: *ast::Node, targetNode: *ast::Node, hint: Type) -> Type
8696
    throws (ResolveError)
8697
{
8698
    let operandTy = try visit(self, targetNode, hint);
8699
    if let case Type::Cell { class, payload } = operandTy {
8700
        if class == types::PointerClass::Unsafe {
8701
            try requireUnsafe(self, targetNode);
8702
        }
8703
        try validateCellPayload(self, node, *payload);
8704
        return setNodeType(self, node, *payload);
8705
    }
8706
    if let case Type::Pointer { class, target, .. } = operandTy {
8707
        if class == types::PointerClass::Unsafe {
8708
            try requireUnsafe(self, targetNode);
8709
        }
8710
        // Disallow dereferencing opaque pointers.
8711
        if *target == Type::Opaque {
8712
            throw emitError(self, targetNode, ErrorKind::OpaqueTypeDeref);
8713
        }
8714
        return setNodeType(self, node, *target);
8715
    }
8716
    // Auto-deref for single-field unlabeled records.
8717
    if let case Type::Nominal(NominalType::Record(recInfo)) = operandTy {
8718
        if not recInfo.labeled and recInfo.fields.len == 1 {
8719
            let fieldTy = recInfo.fields[0].fieldType;
8720
            setRecordFieldIndex(self, node, 0);
8721
            return setNodeType(self, node, fieldTy);
8722
        }
8723
    }
8724
    throw emitError(self, targetNode, ErrorKind::ExpectedPointer);
8725
}
8726
8727
/// Check if a type is a pointer to opaque.
8728
fn isOpaquePointer(ty: Type) -> bool {
8729
    if let case Type::Pointer { target, .. } = ty {
8730
        return *target == Type::Opaque;
8731
    }
8732
    return false;
8733
}
8734
8735
/// Check if a type is an opaque slice.
8736
fn isOpaqueSlice(ty: Type) -> bool {
8737
    if let case Type::Slice { item, .. } = ty {
8738
        return *item == Type::Opaque;
8739
    }
8740
    return false;
8741
}
8742
8743
/// Check if an `as` cast between two types is valid.
8744
unsafe fn isValidCast(source: Type, target: Type) -> bool {
8745
    // Allow identity casts.
8746
    if source == target {
8747
        return true;
8748
    }
8749
    // Allow numeric to numeric.
8750
    if isNumericType(source) and isNumericType(target) {
8751
        return true;
8752
    }
8753
    // Allow `void` union to numeric.
8754
    // TODO: Check that variant index fits in target type.
8755
    if isVoidUnion(source) and isNumericType(target) {
8756
        return true;
8757
    }
8758
    // Allow address to numeric.
8759
    if let case Type::Slice { .. } = source {
8760
        // Disallow slice to numeric; slices are fat pointers.
8761
    } else if isAddressType(source) and isNumericType(target) {
8762
        return true;
8763
    }
8764
    // Allow pointer casts if one side is `*opaque` or target types are castable.
8765
    if let case Type::Pointer {
8766
        class: sourceClass, target: sourceTarget, mutable: sourceMutable,
8767
    } = source {
8768
        if let case Type::Pointer {
8769
            class: targetClass, target: targetTarget, mutable: targetMutable,
8770
        } = target {
8771
            if sourceClass <> targetClass {
8772
                return false;
8773
            }
8774
            if targetMutable and not sourceMutable {
8775
                return false;
8776
            }
8777
            if isOpaquePointer(source) or isOpaquePointer(target) {
8778
                return true;
8779
            }
8780
            return isValidCast(*sourceTarget, *targetTarget);
8781
        }
8782
    }
8783
    // Allow slice casts if one side is `*[opaque]`, target is `*[u8]`,
8784
    // or element types are castable.
8785
    if let case Type::Slice {
8786
        class: sourceClass, item: sourceItem, mutable: sourceMutable,
8787
    } = source {
8788
        if let case Type::Slice {
8789
            class: targetClass, item: targetItem, mutable: targetMutable,
8790
        } = target {
8791
            if sourceClass <> targetClass {
8792
                return false;
8793
            }
8794
            if targetMutable and not sourceMutable {
8795
                return false;
8796
            }
8797
            if isOpaqueSlice(source) or isOpaqueSlice(target) {
8798
                return true;
8799
            }
8800
            if *targetItem == Type::U8 {
8801
                return true;
8802
            }
8803
            return isValidCast(*sourceItem, *targetItem);
8804
        }
8805
    }
8806
    return false;
8807
}
8808
8809
/// Require casts into region-dependent storage to preserve its typed contents.
8810
fn regionalCastPreservesType(source: Type, target: Type) -> bool {
8811
    if typesEqual(source, target) {
8812
        return true;
8813
    }
8814
    if let case Type::Pointer { target: sourceItem, .. } = source {
8815
        let case Type::Pointer { target: targetItem, .. } = target else return false;
8816
        return typesEqual(*sourceItem, *targetItem);
8817
    }
8818
    if let case Type::Slice { item: sourceItem, .. } = source {
8819
        let case Type::Slice { item: targetItem, .. } = target else return false;
8820
        return typesEqual(*sourceItem, *targetItem);
8821
    }
8822
    return false;
8823
}
8824
8825
/// Analyze an `as` cast expression.
8826
unsafe fn resolveAs 'arena (self: &mut Resolver 'arena, node: *ast::Node, expr: ast::As) -> Type
8827
    throws (ResolveError)
8828
{
8829
    let targetTy = try infer(self, expr.type);
8830
    let sourceTy = try visit(self, expr.value, targetTy);
8831
    if isUnsafePointerType(sourceTy) or isUnsafePointerType(targetTy) {
8832
        try requireUnsafe(self, node);
8833
    }
8834
8835
    assert sourceTy <> Type::Unknown;
8836
    assert targetTy <> Type::Unknown;
8837
8838
    if let case Type::Cell { class, payload } = targetTy {
8839
        if let case Type::Pointer { class: sourceClass, target, mutable: true } = sourceTy;
8840
            sourceClass == class and class <> types::PointerClass::Unsafe and typesEqual(*target, *payload)
8841
        {
8842
            return setNodeType(self, node, targetTy);
8843
        }
8844
        if typesEqual(sourceTy, targetTy) {
8845
            return setNodeType(self, node, targetTy);
8846
        }
8847
        throw emitError(self, node, ErrorKind::InvalidAsCast(InvalidAsCast { from: sourceTy, to: targetTy }));
8848
    }
8849
    if containsRegion(targetTy) and not regionalCastPreservesType(sourceTy, targetTy) {
8850
        throw emitError(self, node, ErrorKind::InvalidAsCast(InvalidAsCast {
8851
            from: sourceTy, to: targetTy,
8852
        }));
8853
    }
8854
    let mut valid = isValidCast(sourceTy, targetTy);
8855
    if let case Type::Pointer {
8856
        class: sourceClass, target: sourceTarget, mutable: sourceMutable,
8857
    } = sourceTy {
8858
        if let case Type::Pointer {
8859
            class: targetClass, target: targetTarget, mutable: targetMutable,
8860
        } = targetTy {
8861
            if types::isReference(sourceClass) and
8862
               targetClass == types::PointerClass::Unsafe and
8863
               (not targetMutable or sourceMutable) and
8864
               isValidCast(*sourceTarget, *targetTarget)
8865
            {
8866
                set valid = true;
8867
            }
8868
        }
8869
    }
8870
    if let case Type::Slice {
8871
        class: sourceClass, item: sourceItem, mutable: sourceMutable,
8872
    } = sourceTy {
8873
        if let case Type::Slice {
8874
            class: targetClass, item: targetItem, mutable: targetMutable,
8875
        } = targetTy {
8876
            if types::isReference(sourceClass) and
8877
               targetClass == types::PointerClass::Unsafe and
8878
               (not targetMutable or sourceMutable) and
8879
               isValidCast(*sourceItem, *targetItem)
8880
            {
8881
                set valid = true;
8882
            }
8883
        }
8884
    }
8885
    if valid {
8886
        if let case Type::Pointer { target: sourceTarget, .. } = sourceTy {
8887
            if let case Type::Pointer { target: targetTarget, .. } = targetTy {
8888
                if *targetTarget <> Type::Opaque and not typesEqual(*sourceTarget, *targetTarget) {
8889
                    try requireUnsafe(self, node);
8890
                }
8891
            }
8892
        }
8893
        if let case Type::Slice { item: sourceItem, .. } = sourceTy {
8894
            if let case Type::Slice { item: targetItem, .. } = targetTy {
8895
                if *targetItem <> Type::Opaque and not typesEqual(*sourceItem, *targetItem) {
8896
                    try requireUnsafe(self, node);
8897
                }
8898
            }
8899
        }
8900
        // Propagate the constant value after applying the cast's target-width
8901
        // truncation and signed interpretation.
8902
        if let value = constValueEntry(self, expr.value) {
8903
            if let case ConstValue::Int(i) = value {
8904
                setNodeConstValue(self, node, castConstInt(i, targetTy));
8905
            }
8906
        }
8907
        return setNodeType(self, node, targetTy);
8908
    }
8909
    throw emitError(self, node, ErrorKind::InvalidAsCast(InvalidAsCast {
8910
        from: sourceTy,
8911
        to: targetTy,
8912
    }));
8913
}
8914
8915
/// Analyze a range expression.
8916
unsafe fn resolveRange 'arena (self: &mut Resolver 'arena, node: *ast::Node, range: ast::Range) -> Type
8917
    throws (ResolveError)
8918
{
8919
    let mut start: ?*Type = nil;
8920
    let mut end: ?*Type = nil;
8921
8922
    if let s = range.start {
8923
        let startTy = try checkNumeric(self, s);
8924
8925
        if let e = range.end {
8926
            let endTy = try checkNumeric(self, e);
8927
            let mut resolvedTy = startTy;
8928
8929
            // Infer unsuffixed integer literals from the opposite bound.
8930
            if startTy == Type::Int and endTy <> Type::Int {
8931
                let _ = try checkAssignable(self, s, endTy);
8932
                set resolvedTy = endTy;
8933
            } else if endTy == Type::Int and startTy <> Type::Int {
8934
                let _ = try checkAssignable(self, e, startTy);
8935
                set resolvedTy = startTy;
8936
            } else {
8937
                let _ = try checkAssignable(self, e, startTy);
8938
            }
8939
            set start = allocType(self, resolvedTy);
8940
            set end = allocType(self, resolvedTy);
8941
        } else {
8942
            set start = allocType(self, startTy);
8943
        }
8944
    } else if let e = range.end {
8945
        set end = allocType(self, try checkNumeric(self, e));
8946
    }
8947
    return setNodeType(self, node, Type::Range { start, end });
8948
}
8949
8950
/// Analyze a `try` expression and its handlers.
8951
/// The `expected` type is used to determine if the value is discarded (`Void`)
8952
/// or if the catch expression needs type checking.
8953
unsafe fn resolveTry 'arena (self: &mut Resolver 'arena, node: *ast::Node, tryExpr: ast::Try, hint: Type) -> Type
8954
    throws (ResolveError)
8955
{
8956
    let call = tryExpr.expr;
8957
    let case ast::NodeValue::Call(callExpr) = call.value
8958
        else throw emitError(self, call, ErrorKind::TryNonThrowing);
8959
    let resultTy = try resolveCall(self, call, callExpr, CallCtx::Try, Type::Unknown);
8960
8961
    // TODO: It's annoying that we need to re-fetch the function type after
8962
    // analyzing the call.
8963
    let calleeTy = typeFor(self, callExpr.callee)
8964
        else return setNodeType(self, node, resultTy);
8965
    let case Type::Fn(calleeInfo) = calleeTy
8966
        else throw emitError(self, callExpr.callee, ErrorKind::TryNonThrowing);
8967
8968
    if calleeInfo.throwList.len == 0 {
8969
        throw emitError(self, callExpr.callee, ErrorKind::TryNonThrowing);
8970
    }
8971
    // If we're not catching the error, nor panicking on error, nor returning
8972
    // optional, then the current function must be able to propagate it.
8973
    let mut tryResultTy = resultTy;
8974
    if tryExpr.returnsOptional {
8975
        // `try?` converts errors to `nil` and wraps the result in an optional.
8976
        if let case Type::Optional(_) = resultTy {
8977
            // Already optional, no wrapping needed.
8978
        } else {
8979
            set tryResultTy = Type::Optional(allocType(self, resultTy));
8980
        }
8981
    } else if tryExpr.catches.len > 0 {
8982
        // `try ... catch` -- one or more catch clauses.
8983
        set tryResultTy = try resolveTryCatches(self, node, tryExpr.catches, calleeInfo, resultTy, hint);
8984
    } else if not tryExpr.shouldPanic {
8985
        let fnInfo = self.currentFn
8986
            else throw emitError(self, node, ErrorKind::TryRequiresThrows);
8987
        if fnInfo.throwList.len == 0 {
8988
            throw emitError(self, node, ErrorKind::TryRequiresThrows);
8989
        }
8990
        // Check that *all* thrown errors of the callee can be propagated by
8991
        // the caller.
8992
        for throwTy in calleeInfo.throwList {
8993
            let mut found = false;
8994
8995
            for callerThrowTy in fnInfo.throwList {
8996
                if callerThrowTy == throwTy {
8997
                    set found = true;
8998
                    break;
8999
                }
9000
            }
9001
            if not found {
9002
                throw emitError(self, node, ErrorKind::TryIncompatibleError);
9003
            }
9004
        }
9005
    }
9006
    return setNodeType(self, node, tryResultTy);
9007
}
9008
9009
/// Check that a `catch` body is assignable to the expected result type, but only
9010
/// in expression context (`hint` is neither `Unknown` nor `Void`).
9011
unsafe fn checkCatchBody 'arena (self: &mut Resolver 'arena, body: *ast::Node, resultTy: Type, hint: Type)
9012
    throws (ResolveError)
9013
{
9014
    if hint <> Type::Unknown and hint <> Type::Void {
9015
        try checkAssignable(self, body, resultTy);
9016
    }
9017
}
9018
9019
/// Resolve catch clauses for a `try ... catch` expression.
9020
///
9021
/// For a single untyped catch (with or without binding), resolves the catch
9022
/// body and returns the result type. Multi-error callees with inferred bindings
9023
/// are rejected; you must use typed catches.
9024
unsafe fn resolveTryCatches 'arena (
9025
    self: &mut Resolver 'arena,
9026
    node: *ast::Node,
9027
    catches: *[*ast::Node],
9028
    calleeInfo: *FnType,
9029
    resultTy: Type,
9030
    hint: Type
9031
) -> Type throws (ResolveError) {
9032
    let firstNode = catches[0];
9033
    let case ast::NodeValue::CatchClause(first) = firstNode.value else
9034
        throw emitError(self, node, ErrorKind::UnexpectedNode(firstNode));
9035
9036
    // Typed catches: dispatch to dedicated handler.
9037
    if first.typeNode <> nil {
9038
        return try resolveTypedCatches(self, node, catches, calleeInfo, resultTy, hint);
9039
    }
9040
    // Single untyped catch clause.
9041
    if let binding = first.binding {
9042
        if calleeInfo.throwList.len > 1 {
9043
            throw emitError(self, binding, ErrorKind::TryCatchMultiError);
9044
        }
9045
        enterScope(self, node);
9046
9047
        let errTy = *calleeInfo.throwList[0];
9048
        try bindValueIdent(self, binding, binding, errTy, false, 0, 0);
9049
    }
9050
    let bodyTy = try visit(self, first.body, resultTy);
9051
9052
    if let _ = first.binding {
9053
        exitScope(self);
9054
    }
9055
    try checkCatchBody(self, first.body, resultTy, hint);
9056
9057
    return bodyTy if resultTy == Type::Never else resultTy;
9058
}
9059
9060
/// Resolve typed catch clauses (`catch e as T {..} catch e as S {..}`).
9061
///
9062
/// Validates that each type annotation is in the callee's throw list, that
9063
/// there are no duplicate catch types, and that the clauses are exhaustive.
9064
unsafe fn resolveTypedCatches 'arena (
9065
    self: &mut Resolver 'arena,
9066
    node: *ast::Node,
9067
    catches: *[*ast::Node],
9068
    calleeInfo: *FnType,
9069
    resultTy: Type,
9070
    hint: Type
9071
) -> Type throws (ResolveError) {
9072
    // Track which of the callee's throw types have been covered.
9073
    let mut covered: [bool; MAX_FN_THROWS] = [false; MAX_FN_THROWS];
9074
    let mut hasCatchAll = false;
9075
    let mut catchTy = Type::Never;
9076
9077
    for clauseNode in catches {
9078
        let case ast::NodeValue::CatchClause(clause) = clauseNode.value else
9079
            throw emitError(self, node, ErrorKind::UnexpectedNode(clauseNode));
9080
9081
        if let typeNode = clause.typeNode {
9082
            // Typed catch clause: validate against callee's throw list.
9083
            let errTy = try infer(self, typeNode);
9084
            let mut foundIdx: ?u32 = nil;
9085
9086
            for throwType, j in calleeInfo.throwList {
9087
                if errTy == *throwType {
9088
                    set foundIdx = j;
9089
                    break;
9090
                }
9091
            }
9092
            let idx = foundIdx else {
9093
                throw emitError(self, typeNode, ErrorKind::TryIncompatibleError);
9094
            };
9095
            if covered[idx] {
9096
                throw emitError(self, typeNode, ErrorKind::TryCatchDuplicateType);
9097
            }
9098
            set covered[idx] = true;
9099
9100
            // Bind the error variable if present.
9101
            if let binding = clause.binding {
9102
                enterScope(self, clauseNode);
9103
                try bindValueIdent(self, binding, binding, errTy, false, 0, 0);
9104
            }
9105
        } else {
9106
            // Catch-all clause with no type annotation or binding.
9107
            set hasCatchAll = true;
9108
        }
9109
        // Resolve the catch body and check assignability.
9110
        let bodyTy = try visit(self, clause.body, resultTy);
9111
        if bodyTy <> Type::Never { set catchTy = Type::Void; }
9112
        // Only typed clauses can have bindings.
9113
        if let _ = clause.binding {
9114
            exitScope(self);
9115
        }
9116
        try checkCatchBody(self, clause.body, resultTy, hint);
9117
    }
9118
9119
    // Check exhaustiveness: all callee error types must be covered.
9120
    if not hasCatchAll {
9121
        for i in 0..calleeInfo.throwList.len {
9122
            if not covered[i] {
9123
                throw emitError(self, node, ErrorKind::TryCatchNonExhaustive);
9124
            }
9125
        }
9126
    }
9127
    return catchTy if resultTy == Type::Never else resultTy;
9128
}
9129
9130
/// Analyze a `throw` statement.
9131
unsafe fn resolveThrow 'arena (self: &mut Resolver 'arena, node: *ast::Node, expr: *ast::Node) -> Type
9132
    throws (ResolveError)
9133
{
9134
    let fnInfo = self.currentFn
9135
        else throw emitError(self, node, ErrorKind::ThrowRequiresThrows);
9136
    if fnInfo.throwList.len == 0 {
9137
        throw emitError(self, node, ErrorKind::ThrowRequiresThrows);
9138
    }
9139
    let throwTy = try infer(self, expr);
9140
    for errTy in fnInfo.throwList {
9141
        if let coerce = isAssignable(self, *errTy, throwTy, expr) {
9142
            setNodeCoercion(self, expr, coerce);
9143
            return setNodeType(self, node, Type::Never);
9144
        }
9145
    }
9146
    throw emitError(self, expr, ErrorKind::ThrowIncompatibleError);
9147
}
9148
9149
/// Analyze a `return` statement.
9150
unsafe fn resolveReturn 'arena (self: &mut Resolver 'arena, node: *ast::Node, retVal: ?*ast::Node) -> Type
9151
    throws (ResolveError)
9152
{
9153
    let f = self.currentFn
9154
        else throw emitError(self, node, ErrorKind::UnexpectedReturn);
9155
    let expected = *f.returnType;
9156
9157
    if let val = retVal {
9158
        let _actualTy = try checkAssignable(self, val, expected);
9159
    } else if expected <> Type::Void {
9160
        throw emitTypeMismatch(self, node, TypeMismatch { expected, actual: Type::Void });
9161
    }
9162
    // In throwing functions, return values are wrapped in the success variant.
9163
    if f.throwList.len > 0 {
9164
        setNodeCoercion(self, node, Coercion::ResultWrap);
9165
    }
9166
    return setNodeType(self, node, Type::Never);
9167
}
9168
9169
/// Convert a [`ConstInt`] to its two's-complement bit pattern.
9170
fn constIntToBits(c: ConstInt) -> u64 {
9171
    return (0 - c.magnitude) if c.negative else c.magnitude;
9172
}
9173
9174
/// Convert a [`ConstInt`] to its signed two's-complement representation.
9175
fn constIntToSigned(c: ConstInt) -> i64 {
9176
    return constIntToBits(c) as i64;
9177
}
9178
9179
/// Build a [`ConstInt`] from a signed result, preserving bit width and signedness.
9180
fn constIntFromSigned(value: i64, bits: u8, signed: bool) -> ConstInt {
9181
    if value < 0 {
9182
        // Compute magnitude without signed overflow.
9183
        let uval = value as u64;
9184
        return ConstInt {
9185
            magnitude: 0 - uval,
9186
            bits,
9187
            signed,
9188
            negative: true,
9189
        };
9190
    }
9191
    return ConstInt {
9192
        magnitude: value as u64,
9193
        bits,
9194
        signed,
9195
        negative: false,
9196
    };
9197
}
9198
9199
/// Build a [`ConstInt`] from a two's-complement bit pattern.
9200
fn constIntFromBits(raw: u64, bits: u8, signed: bool) -> ConstInt {
9201
    let mask = parser::U64_MAX if bits == 64 else parser::U64_MAX >> (64 - bits) as u64;
9202
    let truncated = raw & mask;
9203
9204
    if signed {
9205
        let signBit = (mask >> 1) + 1;
9206
        if (truncated & signBit) <> 0 {
9207
            return ConstInt {
9208
                magnitude: (0 - truncated) & mask,
9209
                bits,
9210
                signed,
9211
                negative: true,
9212
            };
9213
        }
9214
    }
9215
    return ConstInt { magnitude: truncated, bits, signed, negative: false };
9216
}
9217
9218
/// Try to fold a binary operation on two integer constants.
9219
/// Returns the resulting constant value if successful.
9220
fn foldIntBinOp(op: ast::BinaryOp, left: ConstInt, right: ConstInt) -> ?ConstValue {
9221
    // Use the wider bit width and propagate signedness.
9222
    let mut bits = left.bits;
9223
    if right.bits > bits {
9224
        set bits = right.bits;
9225
    }
9226
    let signed = left.signed or right.signed;
9227
    let l = constIntToSigned(left);
9228
    let r = constIntToSigned(right);
9229
9230
    match op {
9231
        // Shift counts are masked to the left operand's width, matching
9232
        // the runtime word instructions.
9233
        case ast::BinaryOp::Shl => {
9234
            let raw = constIntToBits(left);
9235
            let shamt = constIntToBits(right) % left.bits as u64;
9236
            return ConstValue::Int(constIntFromBits(raw << shamt, left.bits, left.signed));
9237
        },
9238
        case ast::BinaryOp::Shr => {
9239
            let shamt = constIntToBits(right) % left.bits as u64;
9240
            if left.signed {
9241
                let shifted = constIntToSigned(left) >> shamt as i64;
9242
                return ConstValue::Int(
9243
                    constIntFromBits(shifted as u64, left.bits, true)
9244
                );
9245
            }
9246
            return ConstValue::Int(
9247
                constIntFromBits(left.magnitude >> shamt, left.bits, false)
9248
            );
9249
        },
9250
        case ast::BinaryOp::Eq  => return ConstValue::Bool(l == r),
9251
        case ast::BinaryOp::Ne  => return ConstValue::Bool(l <> r),
9252
        case ast::BinaryOp::Lt =>
9253
            return ConstValue::Bool(l < r if signed else left.magnitude < right.magnitude),
9254
        case ast::BinaryOp::Gt =>
9255
            return ConstValue::Bool(l > r if signed else left.magnitude > right.magnitude),
9256
        case ast::BinaryOp::Lte =>
9257
            return ConstValue::Bool(l <= r if signed else left.magnitude <= right.magnitude),
9258
        case ast::BinaryOp::Gte =>
9259
            return ConstValue::Bool(l >= r if signed else left.magnitude >= right.magnitude),
9260
        case ast::BinaryOp::Add => return ConstValue::Int(constIntFromSigned(l + r, bits, signed)),
9261
        case ast::BinaryOp::Sub => return ConstValue::Int(constIntFromSigned(l - r, bits, signed)),
9262
        case ast::BinaryOp::Mul => return ConstValue::Int(constIntFromSigned(l * r, bits, signed)),
9263
        case ast::BinaryOp::Div => {
9264
            if signed {
9265
                if r == 0 {
9266
                    return nil;
9267
                }
9268
                return ConstValue::Int(constIntFromSigned(l / r, bits, true));
9269
            }
9270
            if right.magnitude == 0 {
9271
                return nil;
9272
            }
9273
            return constInt(left.magnitude / right.magnitude, bits, false, false);
9274
        },
9275
        case ast::BinaryOp::Mod => {
9276
            if signed {
9277
                if r == 0 {
9278
                    return nil;
9279
                }
9280
                return ConstValue::Int(constIntFromSigned(l % r, bits, true));
9281
            }
9282
            if right.magnitude == 0 {
9283
                return nil;
9284
            }
9285
            return constInt(left.magnitude % right.magnitude, bits, false, false);
9286
        },
9287
        case ast::BinaryOp::BitAnd => return ConstValue::Int(constIntFromSigned(l & r, bits, signed)),
9288
        case ast::BinaryOp::BitOr  => return ConstValue::Int(constIntFromSigned(l | r, bits, signed)),
9289
        case ast::BinaryOp::BitXor => return ConstValue::Int(constIntFromSigned(l ^ r, bits, signed)),
9290
        else => return nil,
9291
    }
9292
}
9293
9294
/// Try to constant-fold a binary operation on two resolved operands.
9295
/// Only folds when the result type is concrete.
9296
fn tryFoldBinOp 'arena (self: &mut Resolver 'arena, node: *ast::Node, binop: ast::BinOp, resultTy: Type) {
9297
    let leftVal = constValueEntry(self, binop.left)
9298
        else return;
9299
    let rightVal = constValueEntry(self, binop.right)
9300
        else return;
9301
9302
    // Fold integer binary ops.
9303
    if let case ConstValue::Int(leftInt) = leftVal {
9304
        if let case ConstValue::Int(rightInt) = rightVal {
9305
            if let result = foldIntBinOp(binop.op, leftInt, rightInt) {
9306
                setNodeConstValue(self, node, result);
9307
            }
9308
            return;
9309
        }
9310
    }
9311
9312
    // Fold boolean binary ops.
9313
    if let case ConstValue::Bool(l) = leftVal {
9314
        if let case ConstValue::Bool(r) = rightVal {
9315
            match binop.op {
9316
                case ast::BinaryOp::And => setNodeConstValue(self, node, ConstValue::Bool(l and r)),
9317
                case ast::BinaryOp::Or => setNodeConstValue(self, node, ConstValue::Bool(l or r)),
9318
                case ast::BinaryOp::Eq => setNodeConstValue(self, node, ConstValue::Bool(l == r)),
9319
                case ast::BinaryOp::Ne,
9320
                     ast::BinaryOp::Xor => setNodeConstValue(self, node, ConstValue::Bool(l <> r)),
9321
                else => {}
9322
            }
9323
        }
9324
    }
9325
}
9326
9327
/// Analyze a binary expression.
9328
unsafe fn resolveBinOp 'arena (self: &mut Resolver 'arena, node: *ast::Node, binop: ast::BinOp) -> Type
9329
    throws (ResolveError)
9330
{
9331
    let mut resultTy = Type::Unknown;
9332
9333
    match binop.op {
9334
        case ast::BinaryOp::And,
9335
             ast::BinaryOp::Or,
9336
             ast::BinaryOp::Xor =>
9337
        {
9338
            try checkBoolean(self, binop.left);
9339
            try checkBoolean(self, binop.right);
9340
9341
            set resultTy = Type::Bool;
9342
        },
9343
        case ast::BinaryOp::Eq,
9344
             ast::BinaryOp::Ne =>
9345
        {
9346
            let leftTy = try infer(self, binop.left);
9347
            let rightTy = try visit(self, binop.right, leftTy);
9348
            if isUnsafePointerType(leftTy) or isUnsafePointerType(rightTy) {
9349
                try requireUnsafe(self, node);
9350
            }
9351
9352
            if not isComparable(leftTy, rightTy) {
9353
                throw emitTypeMismatch(self, binop.right, TypeMismatch {
9354
                    expected: leftTy,
9355
                    actual: rightTy,
9356
                });
9357
            }
9358
            // When comparing `T == ?T`, record a coercion on the
9359
            // non-optional side so the lowerer lifts it before comparing.
9360
            // We use the already-optional type from the other side rather than
9361
            // constructing a new optional, so that e.g. `?u8 == 42` coerces
9362
            // `42` to `?u8` (not `?i32`). We also record OptionalLift directly
9363
            // rather than using expectAssignable, because comparisons should
9364
            // allow e.g. `?*mut T == *T` where mutability differs.
9365
            if let case Type::Optional(_) = leftTy {
9366
                if not isOptionalType(rightTy) {
9367
                    setNodeCoercion(self, binop.right, Coercion::OptionalLift(leftTy));
9368
                }
9369
            } else if let case Type::Optional(_) = rightTy {
9370
                setNodeCoercion(self, binop.left, Coercion::OptionalLift(rightTy));
9371
            }
9372
            set resultTy = Type::Bool;
9373
        },
9374
        else => {
9375
            // Check for pointer arithmetic before numeric check.
9376
            if binop.op == ast::BinaryOp::Add or binop.op == ast::BinaryOp::Sub {
9377
                let leftTy = try infer(self, binop.left);
9378
                let rightTy = try visit(self, binop.right, leftTy);
9379
9380
                // Allow arithmetic on owning pointers and unsafe pointers, but
9381
                // never on references.
9382
                if let case Type::Pointer { class: leftClass, target: leftTarget, .. } = leftTy {
9383
                    if *leftTarget == Type::Opaque {
9384
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
9385
                    }
9386
                    if not types::isReference(leftClass)
9387
                        and isNumericType(rightTy)
9388
                    {
9389
                        try requireUnsafe(self, node);
9390
                        return setNodeType(self, node, leftTy);
9391
                    }
9392
                }
9393
                if let case Type::Pointer { class: rightClass, target: rightTarget, .. } = rightTy {
9394
                    if *rightTarget == Type::Opaque {
9395
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
9396
                    }
9397
                    if binop.op == ast::BinaryOp::Add
9398
                        and not types::isReference(rightClass)
9399
                        and isNumericType(leftTy)
9400
                    {
9401
                        try requireUnsafe(self, node);
9402
                        return setNodeType(self, node, rightTy);
9403
                    }
9404
                }
9405
            }
9406
            let leftTy = try checkNumeric(self, binop.left);
9407
            let rightTy = try checkNumeric(self, binop.right);
9408
9409
            let mut operandTy = leftTy;
9410
            if leftTy <> rightTy {
9411
                if leftTy == Type::Int {
9412
                    set operandTy = rightTy;
9413
                } else if rightTy <> Type::Int {
9414
                    throw emitTypeMismatch(self, binop.right, TypeMismatch {
9415
                        expected: leftTy,
9416
                        actual: rightTy,
9417
                    });
9418
                }
9419
            }
9420
9421
            // Ordering comparisons return `bool`, not the operand type.
9422
            match binop.op {
9423
                case ast::BinaryOp::Lt, ast::BinaryOp::Gt,
9424
                     ast::BinaryOp::Lte, ast::BinaryOp::Gte =>
9425
                    set resultTy = Type::Bool,
9426
                else =>
9427
                    set resultTy = operandTy,
9428
            }
9429
9430
        }
9431
    };
9432
    // Try constant folding after both operands are resolved.
9433
    tryFoldBinOp(self, node, binop, resultTy);
9434
9435
    return setNodeType(self, node, resultTy);
9436
}
9437
9438
/// Analyze a unary expression.
9439
unsafe fn resolveUnOp 'arena (self: &mut Resolver 'arena, node: *ast::Node, unop: ast::UnOp) -> Type
9440
    throws (ResolveError)
9441
{
9442
    let mut resultTy = Type::Unknown;
9443
9444
    match unop.op {
9445
        case ast::UnaryOp::Not => {
9446
            set resultTy = try checkBoolean(self, unop.value);
9447
            if let value = constValueEntry(self, unop.value) {
9448
                if let case ConstValue::Bool(val) = value {
9449
                    setNodeConstValue(self, node, ConstValue::Bool(not val));
9450
                }
9451
            }
9452
        },
9453
        case ast::UnaryOp::Neg => {
9454
            // TODO: Check that we're allowed to use `-` here? Should negation
9455
            // only be valid for signed integers?
9456
            set resultTy = try checkNumeric(self, unop.value);
9457
            if let value = constValueEntry(self, unop.value) {
9458
                // Get the constant expression for the value, flip the sign,
9459
                // and store that new expression on the unary op node.
9460
                if let case ConstValue::Int(intVal) = value {
9461
                    setNodeConstValue(
9462
                        self,
9463
                        node,
9464
                        constInt(intVal.magnitude, intVal.bits, true, not intVal.negative)
9465
                    );
9466
                }
9467
            }
9468
        },
9469
        case ast::UnaryOp::BitNot => {
9470
            set resultTy = try checkNumeric(self, unop.value);
9471
            if let value = constValueEntry(self, unop.value) {
9472
                if let case ConstValue::Int(intVal) = value {
9473
                    let signed = constIntToSigned(intVal);
9474
                    let inverted = constIntFromSigned(-(signed + 1), intVal.bits, intVal.signed);
9475
                    setNodeConstValue(self, node, ConstValue::Int(inverted));
9476
                }
9477
            }
9478
        },
9479
    };
9480
    return setNodeType(self, node, resultTy);
9481
}
9482
9483
/// Resolve a type signature node and set its type.
9484
unsafe fn inferTypeSig 'arena (self: &mut Resolver 'arena, node: *ast::Node, sig: ast::TypeSig) -> Type
9485
    throws (ResolveError)
9486
{
9487
    let resolved = try resolveTypeSig(self, node, sig);
9488
9489
    return setNodeType(self, node, resolved);
9490
}
9491
9492
/// Convert a parsed pointer qualifier to its semantic class.
9493
fn resolvePointerClass(class: ast::PointerClass) -> types::PointerClass {
9494
    match class {
9495
        case ast::PointerClass::Owned => return types::PointerClass::Owned,
9496
        case ast::PointerClass::Ref => return types::PointerClass::Ref,
9497
        case ast::PointerClass::Unsafe => return types::PointerClass::Unsafe,
9498
    }
9499
}
9500
9501
/// Convert a type signature node into a type value.
9502
unsafe fn resolveTypeSig 'arena (self: &mut Resolver 'arena, node: *ast::Node, sig: ast::TypeSig) -> Type
9503
    throws (ResolveError)
9504
{
9505
    match sig {
9506
        case ast::TypeSig::Cell { class, payload } => {
9507
            let inner = try infer(self, payload);
9508
            try validateCellPayload(self, node, inner);
9509
            return Type::Cell { class: resolvePointerClass(class), payload: allocType(self, inner) };
9510
        }
9511
        case ast::TypeSig::RegionRef { region, type } => {
9512
            let identity = try resolveRegion(self, region);
9513
            let base = try infer(self, type);
9514
            match base {
9515
                case Type::Cell { payload, .. } =>
9516
                    return Type::Cell { class: types::PointerClass::Region(identity), payload },
9517
                case Type::Pointer { target, mutable, .. } =>
9518
                    return Type::Pointer { class: types::PointerClass::Region(identity), target, mutable },
9519
                case Type::Slice { item, mutable, .. } =>
9520
                    return Type::Slice { class: types::PointerClass::Region(identity), item, mutable },
9521
                case Type::TraitObject { traitInfo, mutable, .. } =>
9522
                    return Type::TraitObject { class: types::PointerClass::Region(identity), traitInfo, mutable },
9523
                else => throw emitError(self, node, ErrorKind::InvalidRefPosition),
9524
            }
9525
        }
9526
        case ast::TypeSig::Applied { name, regions } => {
9527
            if let case ast::NodeValue::Ident(spelling) = name.value;
9528
                mem::eq(spelling, "Session") and findTypeSymbol(self.scope, spelling) == nil
9529
            {
9530
                if regions.len <> 1 {
9531
                    throw emitError(self, node, ErrorKind::RegionArgumentCount(CountMismatch {
9532
                        expected: 1, actual: regions.len,
9533
                    }));
9534
                }
9535
                return Type::Session(try resolveRegion(self, regions[0]));
9536
            }
9537
            let base = try resolveTypeName(self, name);
9538
            return Type::Nominal(try applyNominalRegions(self, base, regions, node));
9539
        }
9540
        case ast::TypeSig::Void => {
9541
            return Type::Void;
9542
        }
9543
        case ast::TypeSig::Never => {
9544
            return Type::Never;
9545
        }
9546
        case ast::TypeSig::Opaque => {
9547
            return Type::Opaque;
9548
        }
9549
        case ast::TypeSig::Bool => {
9550
            return Type::Bool;
9551
        }
9552
        case ast::TypeSig::Integer { width, sign } => {
9553
            let u = sign == ast::Signedness::Unsigned;
9554
            match width {
9555
                case 1 => return Type::U8 if u else Type::I8,
9556
                case 2 => return Type::U16 if u else Type::I16,
9557
                case 4 => return Type::U32 if u else Type::I32,
9558
                case 8 => return Type::U64 if u else Type::I64,
9559
                else => {
9560
                    panic "resolveTypeSig: invalid integer width";
9561
                }
9562
            }
9563
        }
9564
        case ast::TypeSig::Array { itemType, length } => {
9565
            let item = try infer(self, itemType);
9566
            let length = try checkSizeInt(self, length);
9567
9568
            return Type::Array(ArrayType { item: allocType(self, item), length });
9569
        }
9570
        case ast::TypeSig::Slice { class, itemType, mutable } => {
9571
            let item = try infer(self, itemType);
9572
            return Type::Slice {
9573
                class: resolvePointerClass(class),
9574
                item: allocType(self, item),
9575
                mutable,
9576
            };
9577
        }
9578
        case ast::TypeSig::Pointer { class, valueType, mutable } => {
9579
            let target = try infer(self, valueType);
9580
            return Type::Pointer {
9581
                class: resolvePointerClass(class),
9582
                target: allocType(self, target),
9583
                mutable,
9584
            };
9585
        }
9586
        case ast::TypeSig::Optional { valueType } => {
9587
            let payload = try infer(self, valueType);
9588
            return Type::Optional(allocType(self, payload));
9589
        }
9590
        case ast::TypeSig::Nominal(name) => {
9591
            let ty = try resolveTypeName(self, name);
9592
            try requireNominalArguments(self, ty, node);
9593
            return Type::Nominal(ty);
9594
        }
9595
        case ast::TypeSig::Record { fields, labeled } => {
9596
            let mut recordType = try resolveRecordFields(self, node, fields, labeled);
9597
            set recordType.declaredCopy = true;
9598
            for field in recordType.fields {
9599
                if not isCopy(field.fieldType) {
9600
                    set recordType.declaredCopy = false;
9601
                }
9602
            }
9603
            set recordType.regions = self.regionScope;
9604
            let nominalTy = allocNominalType(self, NominalType::Record(recordType));
9605
            if let scope = self.regionScope {
9606
                let map = regionSubstitution(self, scope);
9607
                for parameter, i in scope.entries {
9608
                    set map.arguments[i] = parameter;
9609
                }
9610
                return Type::Nominal(internNominalApplication(self, nominalTy, &map));
9611
            }
9612
            return Type::Nominal(nominalTy);
9613
        }
9614
        case ast::TypeSig::Fn { sig: t, isUnsafe } => {
9615
            let a = alloc::arenaAllocator(self.arena);
9616
            let mut paramTypes: *mut [*Type] = &mut [];
9617
            let mut throwList: *mut [*Type] = &mut [];
9618
9619
            if t.params.len > MAX_FN_PARAMS {
9620
                throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
9621
                    expected: MAX_FN_PARAMS,
9622
                    actual: t.params.len,
9623
                }));
9624
            }
9625
            if t.throwList.len > MAX_FN_THROWS {
9626
                throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch {
9627
                    expected: MAX_FN_THROWS,
9628
                    actual: t.throwList.len,
9629
                }));
9630
            }
9631
9632
            for paramNode in t.params {
9633
                let paramTy = try resolveValueType(self, paramNode);
9634
                paramTypes.append(allocType(self, paramTy), a);
9635
            }
9636
            for tyNode in t.throwList {
9637
                let throwTy = try resolveValueType(self, tyNode);
9638
                try ensureStorableType(self, tyNode, throwTy);
9639
                try validateErrorTag(self, tyNode, throwTy, &throwList[..]);
9640
                throwList.append(allocType(self, throwTy), a);
9641
            }
9642
            let mut retType = allocType(self, Type::Void);
9643
            if let ret = t.returnType {
9644
                let resolvedRet = try resolveValueType(self, ret);
9645
                try ensureStorableType(self, ret, resolvedRet);
9646
                set retType = allocType(self, resolvedRet);
9647
            }
9648
            let fnType = FnType {
9649
                regions: nil,
9650
                paramTypes: &paramTypes[..],
9651
                returnType: retType,
9652
                throwList: &throwList[..],
9653
                isUnsafe,
9654
            };
9655
            return Type::Fn(allocFnType(self, fnType));
9656
        }
9657
        // Resolve an opaque trait object signature.
9658
        case ast::TypeSig::TraitObject { class, traitName, mutable } => {
9659
            let sym = try resolveNamePath(self, traitName);
9660
            let case SymbolData::Trait(traitInfo) = sym.data
9661
                else throw emitError(self, traitName, ErrorKind::Internal);
9662
            setNodeSymbol(self, traitName, sym);
9663
9664
            return Type::TraitObject { class: resolvePointerClass(class), traitInfo, mutable };
9665
        }
9666
    }
9667
}
9668
9669
/// Check if a type can be used for inferrence.
9670
fn isTypeInferrable(type: Type) -> bool {
9671
    if let case Type::Pointer { target, .. } = type {
9672
        return isTypeInferrable(*target);
9673
    }
9674
    match type {
9675
        case Type::Unknown, Type::Nil, Type::Undefined, Type::Int => return false,
9676
        case Type::Array(ary) => return isTypeInferrable(*ary.item),
9677
        case Type::Optional(opt) => return isTypeInferrable(*opt),
9678
        else => return true,
9679
    }
9680
}
9681
9682
/// Analyze a standalone expression by wrapping it in a synthetic function.
9683
export unsafe fn resolveExpr 'arena (
9684
    self: &mut Resolver 'arena, expr: *ast::Node, arena: &mut ast::NodeArena
9685
) -> Diagnostics throws (ResolveError) {
9686
    let a = alloc::arenaAllocator(&mut arena.arena);
9687
    let exprStmt = ast::synthNode(arena, ast::NodeValue::ExprStmt(expr));
9688
    let bodyStmts = ast::nodeSlice(arena, 1).append(exprStmt, a);
9689
    let module = ast::synthFnModule(arena, ANALYZE_EXPR_FN_NAME, bodyStmts);
9690
9691
    let case ast::NodeValue::Block(block) = module.modBody.value
9692
        else panic "resolveExpr: expected block for module body";
9693
    enterScope(self, module.modBody);
9694
    try resolveModuleDecls(self, &block) catch {
9695
        return diagnostics(self);
9696
    };
9697
    try resolveModuleDefs(self, &block) catch {
9698
        return diagnostics(self);
9699
    };
9700
    exitScope(self);
9701
9702
    return diagnostics(self);
9703
}
9704
9705
/// Analyze a parsed module root, ie. a block of top-level statements.
9706
export unsafe fn resolveModuleRoot 'arena (self: &mut Resolver 'arena, root: *ast::Node) -> Diagnostics throws (ResolveError) {
9707
    let case ast::NodeValue::Block(block) = root.value
9708
        else panic "resolveModuleRoot: expected block for module root";
9709
9710
    enterScope(self, root);
9711
    try resolveModuleDecls(self, &block) catch {
9712
        return diagnostics(self);
9713
    };
9714
    try resolveModuleDefs(self, &block) catch {
9715
        return diagnostics(self);
9716
    };
9717
    exitScope(self);
9718
    setNodeType(self, root, Type::Void);
9719
9720
    return diagnostics(self);
9721
}
9722
9723
/// Analyze the module graph. This pass processes `mod` statements, creating symbols
9724
/// and scopes for them, and also binds type names in each module so that cross-module
9725
/// type references work regardless of declaration order.
9726
unsafe fn resolveModuleGraph 'arena (self: &mut Resolver 'arena, block: &ast::Block) throws (ResolveError) {
9727
    try bindTypeNames(self, block);
9728
9729
    for node in block.statements {
9730
        if let case ast::NodeValue::Mod(decl) = node.value {
9731
            try resolveModGraph(self, node, decl);
9732
        }
9733
    }
9734
}
9735
9736
/// Bind all type names in a module.
9737
/// Skips declarations that have already been bound.
9738
unsafe fn bindTypeNames 'arena (self: &mut Resolver 'arena, block: &ast::Block) throws (ResolveError) {
9739
    for node in block.statements {
9740
        match node.value {
9741
            case ast::NodeValue::RecordDecl(decl) => {
9742
                if symbolFor(self, node) == nil {
9743
                    try bindTypeName(self, node, decl.name, decl.attrs) catch {};
9744
                }
9745
            }
9746
            case ast::NodeValue::UnionDecl(decl) => {
9747
                if symbolFor(self, node) == nil {
9748
                    try bindTypeName(self, node, decl.name, decl.attrs) catch {};
9749
                }
9750
            }
9751
            case ast::NodeValue::TraitDecl { name, attrs, .. } => {
9752
                if symbolFor(self, node) == nil {
9753
                    try bindTraitName(self, node, name, attrs) catch {};
9754
                }
9755
            }
9756
            else => {}
9757
        }
9758
    }
9759
}
9760
9761
/// Resolve all type bodies in a module.
9762
unsafe fn resolveTypeBodies 'arena (self: &mut Resolver 'arena, block: &ast::Block) throws (ResolveError) {
9763
    for node in block.statements {
9764
        match node.value {
9765
            case ast::NodeValue::RecordDecl(decl) => {
9766
                try resolveRecordBody(self, node, decl) catch {
9767
                    // Continue resolving other types even if one fails.
9768
                };
9769
            }
9770
            case ast::NodeValue::UnionDecl(decl) => {
9771
                try resolveUnionBody(self, node, decl) catch {
9772
                    // Continue resolving other types even if one fails.
9773
                };
9774
            }
9775
            case ast::NodeValue::TraitDecl { supertraits, methods, .. } => {
9776
                try resolveTraitBody(self, node, supertraits, methods) catch {
9777
                    // Continue resolving other types even if one fails.
9778
                };
9779
            }
9780
            else => {
9781
                // Ignore other declarations.
9782
            }
9783
        }
9784
    }
9785
}
9786
9787
/// Analyze module declarations. This pass processes all top-level statements. When it hits
9788
/// a `mod` statement, it recurses inside the module, analyzing its statements. Module import
9789
/// statements (`use`) are processed here, and make use of the module graph established in the
9790
/// previous pass.
9791
///
9792
/// This function uses a two-phase approach:
9793
/// Phase 1: Bind all type names to allow forward references and mutual recursion.
9794
/// Phase 2: Resolve type bodies, ie. field types, variant types, etc.
9795
unsafe fn resolveModuleDecls 'arena (res: &mut Resolver 'arena, block: &ast::Block) throws (ResolveError) {
9796
    // Phase 1: Bind all type names as placeholders.
9797
    try bindTypeNames(res, block);
9798
    // Phase 2: Process imports so names available from the module graph can
9799
    // be used in function signatures.
9800
    for node in block.statements {
9801
        if let case ast::NodeValue::Use(decl) = node.value {
9802
            try resolveUse(res, node, decl);
9803
        }
9804
    }
9805
    // Phase 3: Bind function signatures so that function references are
9806
    // available in constant and static initializers.
9807
    for node in block.statements {
9808
        if let case ast::NodeValue::FnDecl(decl) = node.value {
9809
            try resolveFnDecl(res, node, decl);
9810
        }
9811
    }
9812
    // Phase 4: Process constants before submodules, so that child modules
9813
    // can reference parent constants via `super::`.
9814
    for node in block.statements {
9815
        if let case ast::NodeValue::ConstDecl(_) = node.value {
9816
            try infer(res, node);
9817
        }
9818
    }
9819
    // Phase 5: Process submodule declarations -- recurses into child modules.
9820
    // Child modules may trigger on-demand type resolution via
9821
    // [`ensureNominalResolved`] which switches to the declaring module's
9822
    // scope.
9823
    for node in block.statements {
9824
        if let case ast::NodeValue::Mod(decl) = node.value {
9825
            try resolveModDecl(res, node, decl);
9826
        }
9827
    }
9828
    // Phase 5b: Process wildcard imports after submodules are resolved,
9829
    // so that transitive re-exports (export use foo::*) are visible.
9830
    for node in block.statements {
9831
        if let case ast::NodeValue::Use(decl) = node.value {
9832
            if decl.wildcard {
9833
                try resolveUse(res, node, decl);
9834
            }
9835
        }
9836
    }
9837
    // Phase 6: Resolve type bodies (record fields, union variants).
9838
    try resolveTypeBodies(res, block);
9839
    // Phase 7: Process all other declarations (statics, etc.).
9840
    for stmt in block.statements {
9841
        try visitDecl(res, stmt);
9842
    }
9843
}
9844
9845
/// Find a tracked binding by symbol identity.
9846
unsafe fn findLinearBinding(env: &LinearEnv, sym: *unsafe mut Symbol) -> ?u32 {
9847
    for i in 0..env.len {
9848
        if env.symbols[i] == sym {
9849
            return i;
9850
        }
9851
    }
9852
    return nil;
9853
}
9854
9855
/// Return whether a tracked binding is still available.
9856
fn linearBindingAvailable(env: &LinearEnv, index: u32) -> bool {
9857
    return (env.available & ((1 as u64) << (index as u64))) <> 0;
9858
}
9859
9860
/// Add a local binding when its resolved type moves by value.
9861
unsafe fn addLinearBinding 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &mut LinearEnv, node: *ast::Node)
9862
    throws (ResolveError) where 'arena: 'checking
9863
{
9864
    let sym = symbolFor(checker.resolver, node) else return;
9865
    let case SymbolData::Value { type: ty, .. } = sym.data else return;
9866
    if not isMoveOnly(ty) {
9867
        return;
9868
    }
9869
    if env.len >= MAX_LINEAR_BINDINGS {
9870
        throw emitError(checker.resolver, node, ErrorKind::Internal);
9871
    }
9872
    set env.symbols[env.len] = sym;
9873
    set env.available |= (1 as u64) << (env.len as u64);
9874
    set env.len += 1;
9875
}
9876
9877
/// Mark a tracked binding as uninitialized.
9878
unsafe fn markLinearBindingUnavailable 'arena (self: &mut Resolver 'arena, env: &mut LinearEnv, node: *ast::Node) {
9879
    let sym = symbolFor(self, node) else return;
9880
    let index = findLinearBinding(env, sym) else return;
9881
    set env.available &= ~((1 as u64) << (index as u64));
9882
}
9883
9884
/// Require exact-use bindings introduced after `start` to be consumed.
9885
unsafe fn finishLinearScope 'arena 'checking (
9886
    checker: &mut LinearChecker 'arena 'checking,
9887
    env: &mut LinearEnv,
9888
    start: u32,
9889
) throws (ResolveError) where 'arena: 'checking {
9890
    if not env.terminated {
9891
        for i in start..env.len {
9892
            if linearBindingAvailable(env, i) {
9893
                let sym = env.symbols[i];
9894
                let case SymbolData::Value { type: ty, .. } = sym.data
9895
                    else panic "finishLinearScope: expected value symbol";
9896
                if isLinear(ty) {
9897
                    throw emitError(
9898
                        checker.resolver,
9899
                        sym.node,
9900
                        ErrorKind::LinearNotConsumed(sym.name),
9901
                    );
9902
                }
9903
            }
9904
        }
9905
    }
9906
    set env.len = start;
9907
}
9908
9909
/// Require a tracked identifier to remain available for any access.
9910
unsafe fn checkLinearIdent 'arena 'checking (
9911
    checker: &mut LinearChecker 'arena 'checking,
9912
    env: &mut LinearEnv,
9913
    node: *ast::Node,
9914
) throws (ResolveError) where 'arena: 'checking {
9915
    let sym = symbolFor(checker.resolver, node) else return;
9916
    let index = findLinearBinding(env, sym) else return;
9917
    if not linearBindingAvailable(env, index) {
9918
        let case SymbolData::Value { type: ty, .. } = sym.data
9919
            else panic "consumeLinearIdent: expected value symbol";
9920
        let kind = ErrorKind::LinearUseAfterConsume(sym.name) if isLinear(ty)
9921
            else ErrorKind::AffineUseAfterMove(sym.name);
9922
        throw emitError(checker.resolver, node, kind);
9923
    }
9924
}
9925
9926
/// Move or consume a tracked identifier once.
9927
unsafe fn consumeLinearIdent 'arena 'checking (
9928
    checker: &mut LinearChecker 'arena 'checking,
9929
    env: &mut LinearEnv,
9930
    node: *ast::Node,
9931
) throws (ResolveError) where 'arena: 'checking {
9932
    try checkLinearIdent(checker, env, node);
9933
    let sym = symbolFor(checker.resolver, node) else return;
9934
    let index = findLinearBinding(env, sym) else return;
9935
    set env.available &= ~((1 as u64) << (index as u64));
9936
}
9937
9938
/// Merge ownership availability across two live branches.
9939
/// Validate both inputs before writing to an output that can alias either input.
9940
unsafe fn joinLinearBranches 'arena 'checking (
9941
    checker: &mut LinearChecker 'arena 'checking,
9942
    env: &mut LinearEnv,
9943
    left: &LinearEnv,
9944
    right: &LinearEnv,
9945
    node: *ast::Node,
9946
) throws (ResolveError) where 'arena: 'checking {
9947
    if left.terminated and right.terminated {
9948
        set *env = *left;
9949
        set env.terminated = true;
9950
        return;
9951
    }
9952
    if left.terminated {
9953
        set *env = *right;
9954
        return;
9955
    }
9956
    if right.terminated {
9957
        set *env = *left;
9958
        return;
9959
    }
9960
    assert left.len == right.len, "joinLinearBranches: scope mismatch";
9961
    let mut available = left.available;
9962
    for i in 0..left.len {
9963
        if linearBindingAvailable(left, i) <> linearBindingAvailable(right, i) {
9964
            let sym = left.symbols[i];
9965
            let case SymbolData::Value { type: ty, .. } = sym.data
9966
                else panic "joinLinearBranches: expected value symbol";
9967
            if isLinear(ty) {
9968
                throw emitError(
9969
                    checker.resolver,
9970
                    node,
9971
                    ErrorKind::LinearBranchMismatch(sym.name),
9972
                );
9973
            }
9974
            set available &= ~((1 as u64) << (i as u64));
9975
        }
9976
    }
9977
    let regionalLoans = left.regionalLoans | right.regionalLoans;
9978
    set *env = *left;
9979
    set env.available = available;
9980
    set env.regionalLoans = regionalLoans;
9981
}
9982
9983
/// Require all available exact-use bindings to be consumed at a function exit.
9984
unsafe fn finishLinearExit 'arena 'checking (
9985
    checker: &mut LinearChecker 'arena 'checking,
9986
    env: &mut LinearEnv,
9987
) throws (ResolveError) where 'arena: 'checking {
9988
    if env.terminated {
9989
        return;
9990
    }
9991
    for i in 0..env.len {
9992
        if linearBindingAvailable(env, i) {
9993
            let sym = env.symbols[i];
9994
            let case SymbolData::Value { type: ty, .. } = sym.data
9995
                else panic "finishLinearExit: expected value symbol";
9996
            if isLinear(ty) {
9997
                throw emitError(
9998
                    checker.resolver,
9999
                    sym.node,
10000
                    ErrorKind::LinearNotConsumed(sym.name),
10001
                );
10002
            }
10003
        }
10004
    }
10005
    set env.terminated = true;
10006
}
10007
10008
/// Find the local root borrowed or consumed by an argument expression.
10009
fn linearRootSymbol 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> ?*unsafe mut Symbol {
10010
    match node.value {
10011
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) =>
10012
            return symbolFor(self, node),
10013
        case ast::NodeValue::As(expr) => return linearRootSymbol(self, expr.value),
10014
        case ast::NodeValue::AddressOf(addr) => return linearRootSymbol(self, addr.target),
10015
        case ast::NodeValue::FieldAccess(access) =>
10016
            return linearRootSymbol(self, access.parent),
10017
        case ast::NodeValue::Subscript { container, .. } =>
10018
            return linearRootSymbol(self, container),
10019
        case ast::NodeValue::Deref(target) => return linearRootSymbol(self, target),
10020
        else => return nil,
10021
    }
10022
}
10023
10024
/// A projection loan that remains active until its named region ends.
10025
record RegionalLoan: Copy {
10026
    /// Address expression that supplies access to the loan.
10027
    source: *ast::Node,
10028
    /// Declared lifetime of the projection.
10029
    region: *unsafe types::Region,
10030
    /// Storage protected by the projection.
10031
    place: BorrowPlace,
10032
    /// Whether accesses through other references are excluded.
10033
    exclusive: bool,
10034
}
10035
10036
/// Return whether a region identity is visible in a lexical environment.
10037
unsafe fn regionInScope(scope: ?*RegionScope, region: *unsafe types::Region) -> bool {
10038
    let mut cursor = scope;
10039
    while let current = cursor {
10040
        for entry in current.entries {
10041
            if entry.id == region.id {
10042
                return true;
10043
            }
10044
        }
10045
        set cursor = current.parent;
10046
    }
10047
    return false;
10048
}
10049
10050
/// Retain only loans whose regions remain active at a control-flow destination.
10051
unsafe fn regionalLoansInScope 'arena 'checking (checker: &LinearChecker 'arena 'checking, mask: u64, scope: ?*RegionScope) -> u64 where 'arena: 'checking {
10052
    let mut result: u64 = 0;
10053
    for i in 0..checker.regionalLen {
10054
        let bit = (1 as u64) << (i as u64);
10055
        if (mask & bit) <> 0 and regionInScope(scope, checker.regional[i].region) {
10056
            set result |= bit;
10057
        }
10058
    }
10059
    return result;
10060
}
10061
10062
/// Remap one loan mask after the regional loan table is compacted.
10063
fn remapRegionalLoans(mask: u64, mapping: &[u64]) -> u64 {
10064
    let mut result: u64 = 0;
10065
    for replacement, i in mapping {
10066
        if (mask & ((1 as u64) << (i as u64))) <> 0 {
10067
            set result |= replacement;
10068
        }
10069
    }
10070
    return result;
10071
}
10072
10073
/// Reclaim ended-region entries and preserve loans for enclosing regions.
10074
unsafe fn compactRegionalLoans 'arena 'checking (
10075
    checker: &mut LinearChecker 'arena 'checking, env: &mut LinearEnv,
10076
    scope: ?*RegionScope
10077
) where 'arena: 'checking {
10078
    let oldLen = checker.regionalLen;
10079
    let mut mapping: [u64; MAX_REGIONAL_LOANS] = [0; MAX_REGIONAL_LOANS];
10080
    let mut next: u32 = 0;
10081
    for i in 0..oldLen {
10082
        let loan = checker.regional[i];
10083
        if regionInScope(scope, loan.region) {
10084
            set checker.regional[next] = loan;
10085
            set mapping[i] = (1 as u64) << (next as u64);
10086
            set next += 1;
10087
        }
10088
    }
10089
    set env.regionalLoans = remapRegionalLoans(env.regionalLoans, &mapping[..oldLen]);
10090
    for i in 0..checker.loopDepth {
10091
        set checker.loopBackLoans[i] = remapRegionalLoans(checker.loopBackLoans[i], &mapping[..oldLen]);
10092
        set checker.loopExitLoans[i] = remapRegionalLoans(checker.loopExitLoans[i], &mapping[..oldLen]);
10093
    }
10094
    set checker.regionalLen = next;
10095
}
10096
10097
/// Check whether an access comes from the reference created by a projection.
10098
unsafe fn usesRegionalLoan 'arena (self: &mut Resolver 'arena, node: *ast::Node, source: *ast::Node) -> bool {
10099
    if node.id == source.id {
10100
        return true;
10101
    }
10102
    let root = linearRootSymbol(self, node) else return false;
10103
    let origin = localReferenceSource(root) else return false;
10104
    return usesRegionalLoan(self, origin, source);
10105
}
10106
10107
/// Retain a full-region projection independently of its local binding scope.
10108
unsafe fn addRegionalLoan 'arena 'checking (
10109
    checker: &mut LinearChecker 'arena 'checking, env: &mut LinearEnv, node: *ast::Node, address: ast::AddressOf
10110
) throws (ResolveError) where 'arena: 'checking {
10111
    let ty = typeFor(checker.resolver, node) else return;
10112
    let mut class = types::PointerClass::Ref;
10113
    match ty {
10114
        case Type::Cell { class: cellClass, .. } => set class = cellClass,
10115
        case Type::Pointer { class: pointerClass, .. } => set class = pointerClass,
10116
        case Type::Slice { class: sliceClass, .. } => set class = sliceClass,
10117
        else => return,
10118
    }
10119
    let case types::PointerClass::Region(region) = class else return;
10120
    let storage = addressStorageClass(checker.resolver, address.target);
10121
    let case types::PointerClass::Region(parent) = storage else return;
10122
    if parent.id <> region.id {
10123
        return;
10124
    }
10125
    let place = borrowPlace(checker.resolver, address.target);
10126
    if place.root == nil {
10127
        return;
10128
    }
10129
    for loan, i in &checker.regional[..checker.regionalLen] {
10130
        if loan.source.id == node.id {
10131
            set env.regionalLoans |= (1 as u64) << (i as u64);
10132
            return;
10133
        }
10134
    }
10135
    if checker.regionalLen >= MAX_REGIONAL_LOANS {
10136
        throw emitError(checker.resolver, node, ErrorKind::RegionalLoanOverflow);
10137
    }
10138
    let index = checker.regionalLen;
10139
    set checker.regional[index] = RegionalLoan { source: node, region, place, exclusive: ast::isExclusiveAddress(address) };
10140
    set checker.regionalLen += 1;
10141
    set env.regionalLoans |= (1 as u64) << (index as u64);
10142
}
10143
10144
/// Return whether an initializer copies a shared reference with a named region.
10145
/// Address expressions and casts retain a loan on their source storage.
10146
unsafe fn copiesRegionalReference(ty: Type, value: *ast::Node) -> bool {
10147
    if referenceRegion(ty) == nil or not isCopy(ty) {
10148
        return false;
10149
    }
10150
    match value.value {
10151
        case ast::NodeValue::AddressOf(_), ast::NodeValue::As(_) => return false,
10152
        else => return true,
10153
    }
10154
}
10155
10156
/// Return the initializer that supplies a local reference's storage.
10157
unsafe fn localReferenceSource(sym: *unsafe mut Symbol) -> ?*ast::Node {
10158
    let case SymbolData::Value { type: ty, .. } = sym.data else return nil;
10159
    if let case Type::Session(_) = ty {
10160
        if let case ast::NodeValue::RegionBinding(binding) = sym.node.value {
10161
            return binding.value;
10162
        }
10163
    }
10164
    if isRefType(ty) {
10165
        if let case ast::NodeValue::Let(binding) = sym.node.value {
10166
            if copiesRegionalReference(ty, binding.value) {
10167
                return nil;
10168
            }
10169
            return binding.value;
10170
        }
10171
        if let case ast::NodeValue::RegionBinding(binding) = sym.node.value {
10172
            return binding.value;
10173
        }
10174
    }
10175
    return nil;
10176
}
10177
10178
/// Resolve a place through reference locals without extending its storage lifetime.
10179
unsafe fn borrowPlace 'arena (self: &mut Resolver 'arena, node: *ast::Node) -> BorrowPlace {
10180
    let mut place = BorrowPlace { root: nil, fields: undefined, len: 0, precise: true };
10181
    match node.value {
10182
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) => {
10183
            let sym = symbolFor(self, node) else return place;
10184
            if let source = localReferenceSource(sym) {
10185
                let origin = borrowPlace(self, source);
10186
                if origin.root <> nil {
10187
                    return origin;
10188
                }
10189
            }
10190
            set place.root = sym;
10191
        }
10192
        case ast::NodeValue::AddressOf(addr) => return borrowPlace(self, addr.target),
10193
        case ast::NodeValue::As(expr) => return borrowPlace(self, expr.value),
10194
        case ast::NodeValue::FieldAccess(access) => {
10195
            set place = borrowPlace(self, access.parent);
10196
            if let ty = typeFor(self, access.parent) {
10197
                if let case Type::Pointer { .. } = ty; not isRefType(ty) and place.len > 0 {
10198
                    set place.len = 0;
10199
                    set place.precise = false;
10200
                }
10201
                if let case Type::Nominal(NominalType::Record(_)) = autoDeref(ty);
10202
                    place.precise and place.len < MAX_BORROW_FIELDS
10203
                {
10204
                    if let index = recordFieldIndexFor(self, access.child) {
10205
                        set place.fields[place.len] = index;
10206
                        set place.len += 1;
10207
                        return place;
10208
                    }
10209
                }
10210
            }
10211
            set place.precise = false;
10212
        }
10213
        case ast::NodeValue::Subscript { container, .. } => {
10214
            set place = borrowPlace(self, container);
10215
            if let ty = typeFor(self, container) {
10216
                if let case Type::Slice { class, .. } = autoDeref(ty); not types::isReference(class) {
10217
                    set place.len = 0;
10218
                }
10219
            }
10220
            set place.precise = false;
10221
        }
10222
        case ast::NodeValue::Deref(target) => {
10223
            set place = borrowPlace(self, target);
10224
            if let ty = typeFor(self, target); not isRefType(ty) and place.len > 0 {
10225
                set place.len = 0;
10226
                set place.precise = false;
10227
            }
10228
        }
10229
        else => {}
10230
    }
10231
    return place;
10232
}
10233
10234
/// Two places overlap unless distinct inline fields prove separation.
10235
fn placesOverlap(left: &BorrowPlace, right: &BorrowPlace) -> bool {
10236
    if left.root == nil or left.root <> right.root {
10237
        return false;
10238
    }
10239
    let count = left.len if left.len < right.len else right.len;
10240
    for i in 0..count {
10241
        if left.fields[i] <> right.fields[i] {
10242
            return false;
10243
        }
10244
    }
10245
    return true;
10246
}
10247
10248
/// Check whether access uses a reference or one of its lexical reborrows.
10249
unsafe fn usesLocalLoan 'arena (self: &mut Resolver 'arena, node: *ast::Node, binding: *unsafe mut Symbol) -> bool {
10250
    let root = linearRootSymbol(self, node) else return false;
10251
    if root == binding {
10252
        return true;
10253
    }
10254
    let source = localReferenceSource(root) else return false;
10255
    return usesLocalLoan(self, source, binding);
10256
}
10257
10258
/// Reject accesses that conflict with a reference in an active lexical scope.
10259
unsafe fn checkLocalLoans 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &LinearEnv, node: *ast::Node, exclusive: bool)
10260
    throws (ResolveError) where 'arena: 'checking
10261
{
10262
    let place = borrowPlace(checker.resolver, node);
10263
    let root = place.root else return;
10264
    for i in 0..checker.regionalLen {
10265
        if (env.regionalLoans & ((1 as u64) << (i as u64))) == 0 {
10266
            continue;
10267
        }
10268
        let loan = checker.regional[i];
10269
        if (exclusive or loan.exclusive) and placesOverlap(&place, &loan.place)
10270
            and not usesRegionalLoan(checker.resolver, node, loan.source)
10271
        {
10272
            throw emitError(checker.resolver, node, ErrorKind::BorrowConflict(root.name));
10273
        }
10274
    }
10275
    for i in 0..checker.localLen {
10276
        let loan = checker.locals[i];
10277
        if (exclusive or loan.exclusive) and placesOverlap(&place, &loan.place)
10278
            and not usesLocalLoan(checker.resolver, node, loan.binding)
10279
        {
10280
            throw emitError(checker.resolver, node, ErrorKind::BorrowConflict(root.name));
10281
        }
10282
    }
10283
}
10284
10285
/// Retain source storage for local borrows and region headers.
10286
unsafe fn addLocalLoan 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &LinearEnv, node: *ast::Node, binding: ast::Let)
10287
    throws (ResolveError) where 'arena: 'checking
10288
{
10289
    let ty = typeFor(checker.resolver, binding.ident) else return;
10290
    if not isRefType(ty) {
10291
        let case Type::Session(_) = ty else return;
10292
        let case ast::NodeValue::RegionBinding(_) = node.value else return;
10293
    }
10294
    if let case ast::NodeValue::Let(_) = node.value;
10295
        copiesRegionalReference(ty, binding.value)
10296
    {
10297
        return;
10298
    }
10299
    let place = borrowPlace(checker.resolver, binding.value);
10300
    if place.root == nil {
10301
        if referenceRegion(ty) <> nil {
10302
            return;
10303
        }
10304
        throw emitError(checker.resolver, node, ErrorKind::RefBinding);
10305
    }
10306
    if checker.localLen >= MAX_LINEAR_BINDINGS {
10307
        throw emitError(checker.resolver, node, ErrorKind::Internal);
10308
    }
10309
    let sym = symbolFor(checker.resolver, node) else panic "reference without binding";
10310
    let mut exclusive = isExclusiveArgument(ty) or createsCellBorrow(binding.value);
10311
    if let case Type::Cell { .. } = ty {
10312
        if let case ast::NodeValue::As(expr) = binding.value.value {
10313
            if let source = typeFor(checker.resolver, expr.value) {
10314
                if let case Type::Pointer { mutable: true, .. } = source {
10315
                    set exclusive = true;
10316
                }
10317
            }
10318
        }
10319
    }
10320
    try checkLocalLoans(checker, env, binding.value, exclusive);
10321
    set checker.locals[checker.localLen] = LocalLoan { binding: sym, place, exclusive };
10322
    set checker.localLen += 1;
10323
}
10324
10325
/// Protect storage borrowed by a pointer pattern until its bindings leave scope.
10326
unsafe fn addPatternLoan 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, subject: *ast::Node)
10327
    throws (ResolveError) where 'arena: 'checking
10328
{
10329
    let ty = typeFor(checker.resolver, subject) else return;
10330
    if unwrapMatchSubject(ty).by == MatchBy::Value {
10331
        return;
10332
    }
10333
    let place = borrowPlace(checker.resolver, subject);
10334
    if place.root == nil {
10335
        return;
10336
    }
10337
    if checker.loanLen >= MAX_LINEAR_BINDINGS {
10338
        throw emitError(checker.resolver, subject, ErrorKind::Internal);
10339
    }
10340
    set checker.loans[checker.loanLen] = place;
10341
    set checker.loanLen += 1;
10342
}
10343
10344
/// Reject a write, mutable loan, or ownership transfer of a pattern source.
10345
unsafe fn checkPatternLoan 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, node: *ast::Node)
10346
    throws (ResolveError) where 'arena: 'checking
10347
{
10348
    let place = borrowPlace(checker.resolver, node);
10349
    let root = place.root else return;
10350
    for i in 0..checker.loanLen {
10351
        if placesOverlap(&checker.loans[i], &place) {
10352
            throw emitError(checker.resolver, node, ErrorKind::BorrowConflict(root.name));
10353
        }
10354
    }
10355
}
10356
10357
/// Return whether a parameter borrows its argument only for the call.
10358
unsafe fn isBorrowedReferenceParameter(ty: Type) -> bool {
10359
    if not isRefType(ty) {
10360
        return false;
10361
    }
10362
    match ty {
10363
        case Type::Cell { class, .. } => return class == types::PointerClass::Ref,
10364
        case Type::Pointer { class, .. } => return class == types::PointerClass::Ref,
10365
        case Type::Slice { class, .. } => return class == types::PointerClass::Ref,
10366
        case Type::TraitObject { class, .. } => return class == types::PointerClass::Ref,
10367
        else => return false,
10368
    }
10369
}
10370
10371
/// Return whether a parameter can mutate or consume its argument's storage.
10372
unsafe fn isExclusiveArgument(ty: Type) -> bool {
10373
    match ty {
10374
        case Type::Pointer { mutable, .. } => return mutable,
10375
        case Type::Slice { mutable, .. } => return mutable,
10376
        case Type::TraitObject { mutable, .. } => return mutable,
10377
        else => return isMoveOnly(ty),
10378
    }
10379
}
10380
10381
/// Add the value identifiers introduced by a pattern.
10382
/// Return whether the pattern introduces references to its source storage.
10383
unsafe fn addLinearPatternBindings 'arena 'checking (
10384
    checker: &mut LinearChecker 'arena 'checking,
10385
    env: &mut LinearEnv,
10386
    pattern: *ast::Node,
10387
) -> bool throws (ResolveError) where 'arena: 'checking {
10388
    let mut hasReferences = false;
10389
    match pattern.value {
10390
        case ast::NodeValue::Ident(_) => {
10391
            try addLinearBinding(checker, env, pattern);
10392
            if let ty = typeFor(checker.resolver, pattern) {
10393
                return isRefType(ty);
10394
            }
10395
        }
10396
        case ast::NodeValue::Call(call) => {
10397
            for arg in call.args {
10398
                if try addLinearPatternBindings(checker, env, arg) {
10399
                    set hasReferences = true;
10400
                }
10401
            }
10402
        }
10403
        case ast::NodeValue::RecordLit(lit) => {
10404
            for fieldNode in lit.fields {
10405
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
10406
                    else panic "addLinearPatternBindings: expected field";
10407
                if try addLinearPatternBindings(checker, env, field.value) {
10408
                    set hasReferences = true;
10409
                }
10410
            }
10411
        }
10412
        case ast::NodeValue::ArrayLit(items) => {
10413
            for item in items {
10414
                if try addLinearPatternBindings(checker, env, item) {
10415
                    set hasReferences = true;
10416
                }
10417
            }
10418
        }
10419
        else => {}
10420
    }
10421
    return hasReferences;
10422
}
10423
10424
/// Check a lexical block and exact-use of locals introduced in it.
10425
unsafe fn checkLinearBlock 'arena 'checking (
10426
    checker: &mut LinearChecker 'arena 'checking,
10427
    env: &mut LinearEnv,
10428
    node: *ast::Node,
10429
) throws (ResolveError) where 'arena: 'checking {
10430
    let start = env.len;
10431
    let localStart = checker.localLen;
10432
    let case ast::NodeValue::Block(block) = node.value
10433
        else panic "checkLinearBlock: expected block";
10434
    for stmt in block.statements {
10435
        if env.terminated {
10436
            break;
10437
        }
10438
        try checkLinearNode(checker, env, stmt, LinearUse::Discard);
10439
    }
10440
    try finishLinearScope(checker, env, start);
10441
    set checker.localLen = localStart;
10442
}
10443
10444
/// Push a repeated-control-flow boundary.
10445
/// Initialize all loop state at this depth before increasing `loopDepth`.
10446
fn enterLinearLoop 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &LinearEnv) where 'arena: 'checking {
10447
    assert checker.loopDepth < MAX_LINEAR_LOOP_DEPTH, "linear loop nesting overflow";
10448
    let depth = checker.loopDepth;
10449
    set checker.loopBackLoans[depth] = 0;
10450
    set checker.loopExitLoans[depth] = 0;
10451
    set checker.loopRegions[depth] = checker.regions;
10452
    set checker.loopMarks[depth] = env.len;
10453
    set checker.loopAvailable[depth] = env.available;
10454
    set checker.loopExitAvailable[depth] = env.available;
10455
    set checker.loopHasNaturalExit[depth] = false;
10456
    set checker.loopBreakSeen[depth] = false;
10457
    set checker.loopDepth += 1;
10458
}
10459
10460
/// Require a repeated body's outer bindings to match its entry state.
10461
unsafe fn checkLinearLoopBackEdge 'arena 'checking (
10462
    checker: &mut LinearChecker 'arena 'checking,
10463
    env: &LinearEnv,
10464
    node: *ast::Node,
10465
) throws (ResolveError) where 'arena: 'checking {
10466
    if env.terminated {
10467
        return;
10468
    }
10469
    assert checker.loopDepth > 0, "linear loop back edge outside loop";
10470
    let depth = checker.loopDepth - 1;
10471
    set checker.loopBackLoans[depth] |= regionalLoansInScope(checker, env.regionalLoans, checker.loopRegions[depth]);
10472
    let mark = checker.loopMarks[depth];
10473
    let entryAvailable = checker.loopAvailable[depth];
10474
    for i in 0..mark {
10475
        let bit = (1 as u64) << (i as u64);
10476
        if (env.available & bit) <> (entryAvailable & bit) {
10477
            let sym = env.symbols[i];
10478
            throw emitError(
10479
                checker.resolver,
10480
                node,
10481
                ErrorKind::LinearBranchMismatch(sym.name),
10482
            );
10483
        }
10484
    }
10485
}
10486
10487
/// Record the ownership state of a loop's condition-false exit.
10488
unsafe fn setLinearLoopNaturalExit 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &LinearEnv) where 'arena: 'checking {
10489
    assert checker.loopDepth > 0, "linear loop exit outside loop";
10490
    let depth = checker.loopDepth - 1;
10491
    set checker.loopExitLoans[depth] |= regionalLoansInScope(checker, env.regionalLoans, checker.loopRegions[depth]);
10492
    set checker.loopExitAvailable[depth] = env.available;
10493
    set checker.loopHasNaturalExit[depth] = true;
10494
}
10495
10496
/// Require a break exit to agree with every other exit from this loop.
10497
unsafe fn checkLinearLoopBreak 'arena 'checking (
10498
    checker: &mut LinearChecker 'arena 'checking,
10499
    env: &LinearEnv,
10500
    node: *ast::Node,
10501
) throws (ResolveError) where 'arena: 'checking {
10502
    assert checker.loopDepth > 0, "linear loop break outside loop";
10503
    let depth = checker.loopDepth - 1;
10504
    set checker.loopExitLoans[depth] |= regionalLoansInScope(checker, env.regionalLoans, checker.loopRegions[depth]);
10505
    let mark = checker.loopMarks[depth];
10506
    if checker.loopHasNaturalExit[depth] or checker.loopBreakSeen[depth] {
10507
        let expected = checker.loopExitAvailable[depth];
10508
        for i in 0..mark {
10509
            let bit = (1 as u64) << (i as u64);
10510
            if (env.available & bit) <> (expected & bit) {
10511
                let sym = env.symbols[i];
10512
                throw emitError(
10513
                    checker.resolver,
10514
                    node,
10515
                    ErrorKind::LinearBranchMismatch(sym.name),
10516
                );
10517
            }
10518
        }
10519
    } else {
10520
        set checker.loopExitAvailable[depth] = env.available;
10521
    }
10522
    set checker.loopBreakSeen[depth] = true;
10523
}
10524
10525
/// Pop a repeated-control-flow boundary.
10526
fn exitLinearLoop 'arena 'checking (checker: &mut LinearChecker 'arena 'checking) where 'arena: 'checking {
10527
    assert checker.loopDepth > 0, "exitLinearLoop: not in loop";
10528
    set checker.loopDepth -= 1;
10529
}
10530
10531
/// Check a conditional and merge its ownership states.
10532
unsafe fn checkLinearIf 'arena 'checking (
10533
    checker: &mut LinearChecker 'arena 'checking,
10534
    env: &mut LinearEnv,
10535
    node: *ast::Node,
10536
    conditional: ast::If,
10537
) throws (ResolveError) where 'arena: 'checking {
10538
    try checkLinearNode(checker, env, conditional.condition, LinearUse::Consume);
10539
    let base = *env;
10540
    let mut thenEnv = base;
10541
    try checkLinearNode(checker, &mut thenEnv, conditional.thenBranch, LinearUse::Discard);
10542
    let mut elseEnv = base;
10543
    if let branch = conditional.elseBranch {
10544
        try checkLinearNode(checker, &mut elseEnv, branch, LinearUse::Discard);
10545
    }
10546
    try joinLinearBranches(checker, env, &thenEnv, &elseEnv, node);
10547
}
10548
10549
/// Check an expression conditional and merge its ownership states.
10550
unsafe fn checkLinearCondExpr 'arena 'checking (
10551
    checker: &mut LinearChecker 'arena 'checking,
10552
    env: &mut LinearEnv,
10553
    node: *ast::Node,
10554
    conditional: ast::CondExpr,
10555
    usage: LinearUse,
10556
) throws (ResolveError) where 'arena: 'checking {
10557
    try checkLinearNode(checker, env, conditional.condition, LinearUse::Consume);
10558
    let base = *env;
10559
    let mut thenEnv = base;
10560
    try checkLinearNode(checker, &mut thenEnv, conditional.thenExpr, usage);
10561
    let mut elseEnv = base;
10562
    try checkLinearNode(checker, &mut elseEnv, conditional.elseExpr, usage);
10563
    try joinLinearBranches(checker, env, &thenEnv, &elseEnv, node);
10564
}
10565
10566
/// Pointer patterns borrow their subject; value patterns consume it.
10567
unsafe fn patternSubjectUse 'arena (self: &Resolver 'arena, subject: *ast::Node) -> LinearUse {
10568
    if let ty = typeFor(self, subject) {
10569
        if let case Type::Pointer { .. } = ty {
10570
            return LinearUse::Borrow;
10571
        }
10572
    }
10573
    return LinearUse::Consume;
10574
}
10575
10576
/// Check a match expression, including ownership transferred into patterns.
10577
unsafe fn checkLinearMatch 'arena 'checking (
10578
    checker: &mut LinearChecker 'arena 'checking,
10579
    env: &mut LinearEnv,
10580
    node: *ast::Node,
10581
    matchExpr: ast::Match,
10582
) throws (ResolveError) where 'arena: 'checking {
10583
    try checkLinearNode(checker, env, matchExpr.subject, patternSubjectUse(checker.resolver, matchExpr.subject));
10584
    let base = *env;
10585
    let mut haveResult = false;
10586
    let mut result = base;
10587
    for prongNode in matchExpr.prongs {
10588
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
10589
            else panic "checkLinearMatch: expected prong";
10590
        let mut branch = base;
10591
        let bindingsStart = branch.len;
10592
        let loanStart = checker.loanLen;
10593
        match prong.arm {
10594
            case ast::ProngArm::Case(patterns) => {
10595
                for pattern in patterns {
10596
                    if try addLinearPatternBindings(checker, &mut branch, pattern) {
10597
                        try addPatternLoan(checker, matchExpr.subject);
10598
                    }
10599
                }
10600
            }
10601
            case ast::ProngArm::Binding(binding) => {
10602
                if try addLinearPatternBindings(checker, &mut branch, binding) {
10603
                    try addPatternLoan(checker, matchExpr.subject);
10604
                }
10605
            }
10606
            case ast::ProngArm::Else => {}
10607
        }
10608
        if prong.guard <> nil {
10609
            for i in bindingsStart..branch.len {
10610
                let sym = branch.symbols[i];
10611
                let case SymbolData::Value { type: ty, .. } = sym.data
10612
                    else panic "checkLinearMatch: expected value symbol";
10613
                if isLinear(ty) {
10614
                    throw emitError(checker.resolver, prongNode, ErrorKind::LinearDiscard);
10615
                }
10616
            }
10617
        }
10618
        if let guard = prong.guard {
10619
            try checkLinearNode(checker, &mut branch, guard, LinearUse::Consume);
10620
        }
10621
        try checkLinearNode(checker, &mut branch, prong.body, LinearUse::Discard);
10622
        try finishLinearScope(checker, &mut branch, bindingsStart);
10623
        set checker.loanLen = loanStart;
10624
        if haveResult {
10625
            let previous = result;
10626
        try joinLinearBranches(checker, &mut result, &previous, &branch, node);
10627
        } else {
10628
            set result = branch;
10629
            set haveResult = true;
10630
        }
10631
    }
10632
    if haveResult {
10633
        set *env = result;
10634
    }
10635
}
10636
10637
/// Check call-scoped loans and argument ownership transfers.
10638
unsafe fn checkLinearCall 'arena 'checking (
10639
    checker: &mut LinearChecker 'arena 'checking,
10640
    env: &mut LinearEnv,
10641
    node: *ast::Node,
10642
    call: ast::Call,
10643
) throws (ResolveError) where 'arena: 'checking {
10644
    match checker.resolver.nodeData.entries[node.id].extra {
10645
        case NodeExtra::SliceAppend { .. }, NodeExtra::SliceDelete { .. } => {
10646
            let case ast::NodeValue::FieldAccess(access) = call.callee.value
10647
                else panic "slice mutation without receiver";
10648
            try checkPatternLoan(checker, access.parent);
10649
            try checkLocalLoans(checker, env, access.parent, true);
10650
        }
10651
        else => {}
10652
    }
10653
    try checkLinearNode(checker, env, call.callee, LinearUse::Observe);
10654
    let mut fnInfo: ?*FnType = nil;
10655
    match checker.resolver.nodeData.entries[node.id].extra {
10656
        case NodeExtra::TraitMethodCall { traitInfo, methodIndex } =>
10657
            set fnInfo = traitInfo.methods[methodIndex].fnType,
10658
        case NodeExtra::MethodCall { method } => set fnInfo = method.fnType,
10659
        else => {
10660
            if let calleeTy = typeFor(checker.resolver, call.callee) {
10661
                if let case Type::Fn(info) = calleeTy {
10662
                    set fnInfo = info;
10663
                }
10664
            }
10665
        }
10666
    }
10667
    let info = fnInfo else {
10668
        for arg in call.args {
10669
            try checkLinearNode(checker, env, arg, LinearUse::Consume);
10670
        }
10671
        return;
10672
    };
10673
    let mut places: [BorrowPlace; MAX_FN_PARAMS + 1] = undefined;
10674
    let mut exclusive: [bool; MAX_FN_PARAMS + 1] = undefined;
10675
    let mut placesLen: u32 = 0;
10676
10677
    // Method function types exclude their implicit receiver. Account for it
10678
    // explicitly so owning receivers are consumed and reference receivers
10679
    // participate in call-scoped loan conflict checks.
10680
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
10681
        let mut receiverClass = types::PointerClass::Unsafe;
10682
        let mut receiverMutable = false;
10683
        let mut haveReceiver = false;
10684
        match checker.resolver.nodeData.entries[node.id].extra {
10685
            case NodeExtra::TraitMethodCall { traitInfo, methodIndex } => {
10686
                let method = &traitInfo.methods[methodIndex];
10687
                set receiverClass = method.receiverClass;
10688
                set receiverMutable = method.mutable;
10689
                set haveReceiver = true;
10690
            }
10691
            case NodeExtra::MethodCall { method } => {
10692
                set receiverClass = method.receiverClass;
10693
                set receiverMutable = method.mutable;
10694
                set haveReceiver = true;
10695
            }
10696
            else => {}
10697
        }
10698
        if haveReceiver {
10699
            try checkLocalLoans(checker, env, access.parent,
10700
                receiverMutable or receiverClass == types::PointerClass::Owned);
10701
            if receiverMutable or receiverClass == types::PointerClass::Owned {
10702
                try checkPatternLoan(checker, access.parent);
10703
            }
10704
            if receiverClass <> types::PointerClass::Unsafe {
10705
                let place = borrowPlace(checker.resolver, access.parent);
10706
                if place.root <> nil {
10707
                    set places[placesLen] = place;
10708
                    set exclusive[placesLen] =
10709
                        receiverClass == types::PointerClass::Owned or receiverMutable;
10710
                    set placesLen += 1;
10711
                }
10712
            }
10713
            if types::isReference(receiverClass) {
10714
                try checkLinearNode(checker, env, access.parent, LinearUse::Borrow);
10715
            } else if receiverClass == types::PointerClass::Owned {
10716
                try checkLinearNode(checker, env, access.parent, LinearUse::Consume);
10717
            }
10718
        }
10719
    }
10720
10721
    for arg, i in call.args {
10722
        let expected = *info.paramTypes[i];
10723
        let argExclusive = isExclusiveArgument(expected) or createsCellBorrow(arg);
10724
        if argExclusive {
10725
            try checkPatternLoan(checker, arg);
10726
        }
10727
        let place = borrowPlace(checker.resolver, arg);
10728
        if not isUnsafePointerType(expected) {
10729
            if let rootSym = place.root {
10730
                for j in 0..placesLen {
10731
                    if (exclusive[j] or argExclusive) and placesOverlap(&places[j], &place) {
10732
                        throw emitError(checker.resolver, arg, ErrorKind::BorrowConflict(rootSym.name));
10733
                    }
10734
                }
10735
                set places[placesLen] = place;
10736
                set exclusive[placesLen] = argExclusive;
10737
                set placesLen += 1;
10738
            }
10739
        }
10740
        try checkLocalLoans(checker, env, arg, argExclusive);
10741
        if isBorrowedReferenceParameter(expected) {
10742
            try checkLinearNode(checker, env, arg, LinearUse::Borrow);
10743
        } else {
10744
            try checkLinearNode(checker, env, arg, LinearUse::Consume);
10745
        }
10746
    }
10747
    if *info.returnType == Type::Never and info.throwList.len == 0 {
10748
        set env.terminated = true;
10749
    }
10750
}
10751
10752
/// Check a pattern conditional. Linear scrutinees require an exhaustive match.
10753
unsafe fn checkLinearIfLet 'arena 'checking (
10754
    checker: &mut LinearChecker 'arena 'checking,
10755
    env: &mut LinearEnv,
10756
    node: *ast::Node,
10757
    conditional: ast::IfLet,
10758
) throws (ResolveError) where 'arena: 'checking {
10759
    if let subjectTy = typeFor(checker.resolver, conditional.pattern.scrutinee);
10760
        isLinear(subjectTy)
10761
    {
10762
        throw emitError(
10763
            checker.resolver,
10764
            conditional.pattern.scrutinee,
10765
            ErrorKind::LinearPartialMove,
10766
        );
10767
    }
10768
    try checkLinearNode(
10769
        checker,
10770
        env,
10771
        conditional.pattern.scrutinee,
10772
        patternSubjectUse(checker.resolver, conditional.pattern.scrutinee),
10773
    );
10774
    let base = *env;
10775
    let mut thenEnv = base;
10776
    let bindingsStart = thenEnv.len;
10777
    let loanStart = checker.loanLen;
10778
    if try addLinearPatternBindings(checker, &mut thenEnv, conditional.pattern.pattern) {
10779
        try addPatternLoan(checker, conditional.pattern.scrutinee);
10780
    }
10781
    if let guard = conditional.pattern.guard {
10782
        try checkLinearNode(checker, &mut thenEnv, guard, LinearUse::Consume);
10783
    }
10784
    try checkLinearNode(checker, &mut thenEnv, conditional.thenBranch, LinearUse::Discard);
10785
    try finishLinearScope(checker, &mut thenEnv, bindingsStart);
10786
    set checker.loanLen = loanStart;
10787
    let mut elseEnv = base;
10788
    if let branch = conditional.elseBranch {
10789
        try checkLinearNode(checker, &mut elseEnv, branch, LinearUse::Discard);
10790
    }
10791
    try joinLinearBranches(checker, env, &thenEnv, &elseEnv, node);
10792
}
10793
10794
/// Check a repeated region-loan flow until its loop-entry mask is stable.
10795
/// Each additional pass must add a bit from the bounded regional loan table.
10796
unsafe fn checkLinearLoop 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &mut LinearEnv, node: *ast::Node)
10797
    throws (ResolveError) where 'arena: 'checking
10798
{
10799
    if let case ast::NodeValue::For(forStmt) = node.value {
10800
        try checkLinearNode(checker, env, forStmt.iterable, LinearUse::Consume);
10801
    }
10802
    let base = *env;
10803
    let depth = checker.loopDepth;
10804
    let mut entryLoans = base.regionalLoans;
10805
    loop {
10806
        let mut pass = base;
10807
        set pass.regionalLoans = entryLoans;
10808
        try checkLinearLoopPass(checker, &mut pass, node);
10809
        let next = entryLoans | checker.loopBackLoans[depth];
10810
        if next == entryLoans {
10811
            set *env = pass;
10812
            return;
10813
        }
10814
        set entryLoans = next;
10815
    }
10816
}
10817
10818
/// Check one pass through a loop with the current loop-entry loan state.
10819
unsafe fn checkLinearLoopPass 'arena 'checking (checker: &mut LinearChecker 'arena 'checking, env: &mut LinearEnv, node: *ast::Node)
10820
    throws (ResolveError) where 'arena: 'checking
10821
{
10822
    match node.value {
10823
        case ast::NodeValue::While(whileStmt) => {
10824
            enterLinearLoop(checker, env);
10825
            try checkLinearNode(checker, env, whileStmt.condition, LinearUse::Consume);
10826
            let conditionExit = *env;
10827
            setLinearLoopNaturalExit(checker, &conditionExit);
10828
            let mut bodyEnv = conditionExit;
10829
            try checkLinearNode(checker, &mut bodyEnv, whileStmt.body, LinearUse::Discard);
10830
            try checkLinearLoopBackEdge(checker, &bodyEnv, whileStmt.body);
10831
            exitLinearLoop(checker);
10832
            set *env = conditionExit;
10833
            set env.regionalLoans = checker.loopExitLoans[checker.loopDepth];
10834
            if let elseBranch = whileStmt.elseBranch {
10835
                let mut elseEnv = conditionExit;
10836
                try checkLinearNode(
10837
                    checker,
10838
                    &mut elseEnv,
10839
                    elseBranch,
10840
                    LinearUse::Discard,
10841
                );
10842
                let exits = *env;
10843
                try joinLinearBranches(checker, env, &exits, &elseEnv, node);
10844
            }
10845
        }
10846
        case ast::NodeValue::WhileLet(whileStmt) => {
10847
            if let subjectTy = typeFor(checker.resolver, whileStmt.pattern.scrutinee);
10848
                isLinear(subjectTy)
10849
            {
10850
                throw emitError(
10851
                    checker.resolver,
10852
                    whileStmt.pattern.scrutinee,
10853
                    ErrorKind::LinearPartialMove,
10854
                );
10855
            }
10856
            let base = *env;
10857
            enterLinearLoop(checker, env);
10858
            let mut bodyEnv = base;
10859
            try checkLinearNode(
10860
                checker,
10861
                &mut bodyEnv,
10862
                whileStmt.pattern.scrutinee,
10863
                patternSubjectUse(checker.resolver, whileStmt.pattern.scrutinee),
10864
            );
10865
            let mut conditionExit = bodyEnv;
10866
            let start = bodyEnv.len;
10867
            let loanStart = checker.loanLen;
10868
            if try addLinearPatternBindings(checker, &mut bodyEnv, whileStmt.pattern.pattern) {
10869
                try addPatternLoan(checker, whileStmt.pattern.scrutinee);
10870
            }
10871
            if let guard = whileStmt.pattern.guard {
10872
                try checkLinearNode(checker, &mut bodyEnv, guard, LinearUse::Consume);
10873
                let mut guardExit = bodyEnv;
10874
                try finishLinearScope(checker, &mut guardExit, start);
10875
                let previous = conditionExit;
10876
                try joinLinearBranches(
10877
                    checker,
10878
                    &mut conditionExit,
10879
                    &previous,
10880
                    &guardExit,
10881
                    guard,
10882
                );
10883
            }
10884
            setLinearLoopNaturalExit(checker, &conditionExit);
10885
            try checkLinearNode(checker, &mut bodyEnv, whileStmt.body, LinearUse::Discard);
10886
            try finishLinearScope(checker, &mut bodyEnv, start);
10887
            set checker.loanLen = loanStart;
10888
            try checkLinearLoopBackEdge(checker, &bodyEnv, whileStmt.body);
10889
            exitLinearLoop(checker);
10890
            set *env = conditionExit;
10891
            set env.regionalLoans = checker.loopExitLoans[checker.loopDepth];
10892
            if let elseBranch = whileStmt.elseBranch {
10893
                let mut elseEnv = conditionExit;
10894
                try checkLinearNode(
10895
                    checker,
10896
                    &mut elseEnv,
10897
                    elseBranch,
10898
                    LinearUse::Discard,
10899
                );
10900
                let exits = *env;
10901
                try joinLinearBranches(checker, env, &exits, &elseEnv, node);
10902
            }
10903
        }
10904
        case ast::NodeValue::For(forStmt) => {
10905
            if let iterableTy = typeFor(checker.resolver, forStmt.iterable) {
10906
                if isLinear(iterableTy) {
10907
                    throw emitError(
10908
                        checker.resolver,
10909
                        forStmt.iterable,
10910
                        ErrorKind::LinearPartialMove,
10911
                    );
10912
                }
10913
            }
10914
            let base = *env;
10915
            enterLinearLoop(checker, env);
10916
            setLinearLoopNaturalExit(checker, &base);
10917
            let mut bodyEnv = base;
10918
            let start = bodyEnv.len;
10919
            try addLinearBinding(checker, &mut bodyEnv, forStmt.binding);
10920
            if let index = forStmt.index {
10921
                try addLinearBinding(checker, &mut bodyEnv, index);
10922
            }
10923
            try checkLinearNode(checker, &mut bodyEnv, forStmt.body, LinearUse::Discard);
10924
            try finishLinearScope(checker, &mut bodyEnv, start);
10925
            try checkLinearLoopBackEdge(checker, &bodyEnv, forStmt.body);
10926
            exitLinearLoop(checker);
10927
            set *env = base;
10928
            set env.regionalLoans = checker.loopExitLoans[checker.loopDepth];
10929
            if let elseBranch = forStmt.elseBranch {
10930
                let mut elseEnv = base;
10931
                try checkLinearNode(
10932
                    checker,
10933
                    &mut elseEnv,
10934
                    elseBranch,
10935
                    LinearUse::Discard,
10936
                );
10937
                let exits = *env;
10938
                try joinLinearBranches(checker, env, &exits, &elseEnv, node);
10939
            }
10940
        }
10941
        case ast::NodeValue::Loop { body } => {
10942
            let base = *env;
10943
            enterLinearLoop(checker, env);
10944
            let mut bodyEnv = base;
10945
            try checkLinearNode(checker, &mut bodyEnv, body, LinearUse::Discard);
10946
            try checkLinearLoopBackEdge(checker, &bodyEnv, body);
10947
            let depth = checker.loopDepth - 1;
10948
            let breakSeen = checker.loopBreakSeen[depth];
10949
            let exitAvailable = checker.loopExitAvailable[depth];
10950
            exitLinearLoop(checker);
10951
            set *env = base;
10952
            set env.regionalLoans = checker.loopExitLoans[checker.loopDepth];
10953
            if breakSeen {
10954
                set env.available = exitAvailable;
10955
            } else {
10956
                set env.terminated = true;
10957
            }
10958
        }
10959
        else => panic "checkLinearLoopPass: expected loop",
10960
    }
10961
}
10962
10963
/// Transfer a cell's owning handle and check each address operand once.
10964
unsafe fn checkCellAddressOwner 'arena 'checking (
10965
    checker: &mut LinearChecker 'arena 'checking, env: &mut LinearEnv,
10966
    node: *ast::Node, owner: *ast::Node
10967
) throws (ResolveError) where 'arena: 'checking {
10968
    if node == owner {
10969
        try checkLinearNode(checker, env, node, LinearUse::Consume);
10970
        return;
10971
    }
10972
    match node.value {
10973
        case ast::NodeValue::Deref(target) => try checkCellAddressOwner(checker, env, target, owner),
10974
        case ast::NodeValue::FieldAccess(access) => try checkCellAddressOwner(checker, env, access.parent, owner),
10975
        case ast::NodeValue::Subscript { container, index } => {
10976
            try checkCellAddressOwner(checker, env, container, owner);
10977
            try checkLinearNode(checker, env, index, LinearUse::Consume);
10978
        }
10979
        else => panic "cell address owner must belong to its place",
10980
    }
10981
}
10982
10983
/// Check one expression or statement under an ownership-use context.
10984
unsafe fn checkLinearNode 'arena 'checking (
10985
    checker: &mut LinearChecker 'arena 'checking,
10986
    env: &mut LinearEnv,
10987
    node: *ast::Node,
10988
    usage: LinearUse,
10989
) throws (ResolveError) where 'arena: 'checking {
10990
    if env.terminated {
10991
        return;
10992
    }
10993
    if usage <> LinearUse::Locate {
10994
        match node.value {
10995
            case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_),
10996
                 ast::NodeValue::FieldAccess(_), ast::NodeValue::Subscript { .. },
10997
                 ast::NodeValue::Deref(_) => {
10998
                let mut exclusive = usage == LinearUse::Place and not isCellDeref(checker.resolver, node);
10999
                if usage == LinearUse::Consume {
11000
                    if let ty = typeFor(checker.resolver, node) {
11001
                        set exclusive = isExclusiveArgument(ty);
11002
                    }
11003
                }
11004
                try checkLocalLoans(checker, env, node, exclusive);
11005
            }
11006
            else => {}
11007
        }
11008
    }
11009
    match node.value {
11010
        case ast::NodeValue::Ident(_) => {
11011
            if usage <> LinearUse::Place {
11012
                try checkLinearIdent(checker, env, node);
11013
            }
11014
            if usage == LinearUse::Consume {
11015
                if let ty = typeFor(checker.resolver, node); isExclusiveArgument(ty) {
11016
                    try checkPatternLoan(checker, node);
11017
                }
11018
                try consumeLinearIdent(checker, env, node);
11019
            }
11020
        }
11021
        case ast::NodeValue::ExprStmt(expr) => {
11022
            if let exprTy = typeFor(checker.resolver, expr) {
11023
                if isLinear(exprTy) {
11024
                    throw emitError(checker.resolver, expr, ErrorKind::LinearDiscard);
11025
                }
11026
            }
11027
            try checkLinearNode(checker, env, expr, LinearUse::Consume);
11028
        }
11029
        case ast::NodeValue::RegionBlock { bindings, body, .. } => {
11030
            let previousRegions = checker.regions;
11031
            let case NodeExtra::Regions(scope) = checker.resolver.nodeData.entries[node.id].extra else {
11032
                if checker.resolver.errors.len > 0 {
11033
                    return;
11034
                }
11035
                panic "checkLinearNode: missing region scope";
11036
            };
11037
            set checker.regions = scope;
11038
            let start = env.len;
11039
            let localStart = checker.localLen;
11040
            for bindingNode in bindings {
11041
                let case ast::NodeValue::RegionBinding(binding) = bindingNode.value
11042
                    else panic "checkLinearNode: invalid borrow binding";
11043
                try checkLinearNode(checker, env, binding.value, LinearUse::Consume);
11044
                if env.terminated {
11045
                    break;
11046
                }
11047
                try addLinearBinding(checker, env, bindingNode);
11048
                try addLocalLoan(checker, env, bindingNode, ast::borrowBinding(binding));
11049
            }
11050
            try checkLinearBlock(checker, env, body);
11051
            try finishLinearScope(checker, env, start);
11052
            set checker.localLen = localStart;
11053
            set checker.regions = previousRegions;
11054
            compactRegionalLoans(checker, env, previousRegions);
11055
        }
11056
        case ast::NodeValue::Block(_) => try checkLinearBlock(checker, env, node),
11057
        case ast::NodeValue::Let(binding) => {
11058
            let mut isUndefined = false;
11059
            if let case ast::NodeValue::Undef = binding.value.value {
11060
                set isUndefined = true;
11061
            }
11062
            if isUndefined {
11063
                if let bindingTy = typeFor(checker.resolver, binding.ident);
11064
                    isLinear(bindingTy)
11065
                {
11066
                    throw emitError(
11067
                        checker.resolver,
11068
                        binding.value,
11069
                        ErrorKind::LinearUndefined,
11070
                    );
11071
                }
11072
            }
11073
            try checkLinearNode(checker, env, binding.value, LinearUse::Consume);
11074
            if env.terminated {
11075
                return;
11076
            }
11077
            try addLinearBinding(checker, env, node);
11078
            try addLocalLoan(checker, env, node, binding);
11079
            if isUndefined {
11080
                markLinearBindingUnavailable(checker.resolver, env, node);
11081
            }
11082
        }
11083
        case ast::NodeValue::Assign(assign) => {
11084
            if not isCellDeref(checker.resolver, assign.left) {
11085
                try checkPatternLoan(checker, assign.left);
11086
            }
11087
            let mut target: ?u32 = nil;
11088
            let mut targetLinear = false;
11089
            if let leftTy = typeFor(checker.resolver, assign.left) {
11090
                if isMoveOnly(leftTy) {
11091
                    set targetLinear = isLinear(leftTy);
11092
                    if let case ast::NodeValue::Ident(_) = assign.left.value {
11093
                        if let sym = symbolFor(checker.resolver, assign.left) {
11094
                            set target = findLinearBinding(env, sym);
11095
                        }
11096
                    }
11097
                    if targetLinear and target == nil {
11098
                        throw emitError(
11099
                            checker.resolver,
11100
                            assign.left,
11101
                            ErrorKind::LinearOverwrite,
11102
                        );
11103
                    }
11104
                }
11105
            }
11106
            try checkLinearNode(checker, env, assign.left, LinearUse::Place);
11107
            try checkLinearNode(checker, env, assign.right, LinearUse::Consume);
11108
            if let index = target {
11109
                if targetLinear and linearBindingAvailable(env, index) {
11110
                    throw emitError(
11111
                        checker.resolver,
11112
                        assign.left,
11113
                        ErrorKind::LinearOverwrite,
11114
                    );
11115
                }
11116
                set env.available |= (1 as u64) << (index as u64);
11117
            }
11118
        }
11119
        case ast::NodeValue::RegionApply { value, .. } =>
11120
            try checkLinearNode(checker, env, value, usage),
11121
        case ast::NodeValue::Call(call) => try checkLinearCall(checker, env, node, call),
11122
        case ast::NodeValue::AddressOf(addr) => {
11123
            try checkLocalLoans(checker, env, addr.target, ast::isExclusiveAddress(addr));
11124
            if ast::isExclusiveAddress(addr) {
11125
                try checkPatternLoan(checker, addr.target);
11126
            }
11127
            let mut owner: ?*ast::Node = nil;
11128
            if addr.kind == ast::AddressKind::Cell {
11129
                if let ty = typeFor(checker.resolver, node) {
11130
                    if let case Type::Cell { class: types::PointerClass::Owned, .. } = ty {
11131
                        set owner = addressOwner(checker.resolver, addr.target);
11132
                    }
11133
                }
11134
            }
11135
            if let source = owner {
11136
                try checkCellAddressOwner(checker, env, addr.target, source);
11137
            } else {
11138
                try checkLinearNode(checker, env, addr.target, LinearUse::Locate);
11139
            }
11140
            try addRegionalLoan(checker, env, node, addr);
11141
        }
11142
        case ast::NodeValue::Deref(target) => {
11143
            if let resultTy = typeFor(checker.resolver, node) {
11144
                if isMoveOnly(resultTy) and usage == LinearUse::Consume {
11145
                    throw emitError(checker.resolver, node, ErrorKind::LinearPartialMove);
11146
                }
11147
            }
11148
            try checkLinearNode(checker, env, target, LinearUse::Locate);
11149
        }
11150
        case ast::NodeValue::FieldAccess(access) => {
11151
            if let resultTy = typeFor(checker.resolver, node) {
11152
                if isMoveOnly(resultTy) and usage == LinearUse::Consume {
11153
                    throw emitError(checker.resolver, node, ErrorKind::LinearPartialMove);
11154
                }
11155
            }
11156
            try checkLinearNode(checker, env, access.parent, LinearUse::Locate);
11157
        }
11158
        case ast::NodeValue::ScopeAccess(_) => {}
11159
        case ast::NodeValue::Subscript { container, index } => {
11160
            if let resultTy = typeFor(checker.resolver, node) {
11161
                if isMoveOnly(resultTy) and usage == LinearUse::Consume {
11162
                    throw emitError(checker.resolver, node, ErrorKind::LinearPartialMove);
11163
                }
11164
            }
11165
            try checkLinearNode(checker, env, container, LinearUse::Locate);
11166
            try checkLinearNode(checker, env, index, LinearUse::Consume);
11167
        }
11168
        case ast::NodeValue::RecordLit(lit) => {
11169
            for fieldNode in lit.fields {
11170
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
11171
                    else panic "checkLinearNode: expected field";
11172
                try checkLinearNode(checker, env, field.value, LinearUse::Consume);
11173
            }
11174
        }
11175
        case ast::NodeValue::ArrayLit(items) => {
11176
            for item in items {
11177
                try checkLinearNode(checker, env, item, LinearUse::Consume);
11178
            }
11179
        }
11180
        case ast::NodeValue::ArrayRepeatLit(repeat) => {
11181
            if let itemTy = typeFor(checker.resolver, repeat.item) {
11182
                if not isCopy(itemTy) {
11183
                    throw emitError(
11184
                        checker.resolver,
11185
                        repeat.item,
11186
                        ErrorKind::LinearDiscard,
11187
                    );
11188
                }
11189
            }
11190
            try checkLinearNode(checker, env, repeat.item, LinearUse::Consume);
11191
            try checkLinearNode(checker, env, repeat.count, LinearUse::Consume);
11192
        }
11193
        case ast::NodeValue::BinOp(op) => {
11194
            let mut operandUse = LinearUse::Consume;
11195
            match op.op {
11196
                case ast::BinaryOp::Eq, ast::BinaryOp::Ne,
11197
                     ast::BinaryOp::Lt, ast::BinaryOp::Gt,
11198
                     ast::BinaryOp::Lte, ast::BinaryOp::Gte =>
11199
                    set operandUse = LinearUse::Observe,
11200
                else => {}
11201
            }
11202
            try checkLinearNode(checker, env, op.left, operandUse);
11203
            try checkLinearNode(checker, env, op.right, operandUse);
11204
        }
11205
        case ast::NodeValue::UnOp(op) => {
11206
            try checkLinearNode(checker, env, op.value, LinearUse::Consume);
11207
        }
11208
        case ast::NodeValue::As(expr) => {
11209
            let mut castUse = usage;
11210
            if let targetTy = typeFor(checker.resolver, node) {
11211
                if let case Type::Cell { .. } = targetTy {
11212
                    set castUse = LinearUse::Consume;
11213
                }
11214
            }
11215
            if let targetTy = typeFor(checker.resolver, node); isNumericType(targetTy) {
11216
                set castUse = LinearUse::Observe;
11217
            }
11218
            try checkLinearNode(checker, env, expr.value, castUse);
11219
        }
11220
        case ast::NodeValue::Range(range) => {
11221
            if let start = range.start {
11222
                try checkLinearNode(checker, env, start, LinearUse::Consume);
11223
            }
11224
            if let end = range.end {
11225
                try checkLinearNode(checker, env, end, LinearUse::Consume);
11226
            }
11227
        }
11228
        case ast::NodeValue::BuiltinCall { args, .. } => {
11229
            for arg in args {
11230
                try checkLinearNode(checker, env, arg, LinearUse::Consume);
11231
            }
11232
        }
11233
        case ast::NodeValue::If(conditional) => {
11234
            try checkLinearIf(checker, env, node, conditional);
11235
        }
11236
        case ast::NodeValue::CondExpr(conditional) => {
11237
            try checkLinearCondExpr(checker, env, node, conditional, usage);
11238
        }
11239
        case ast::NodeValue::IfLet(conditional) => {
11240
            try checkLinearIfLet(checker, env, node, conditional);
11241
        }
11242
        case ast::NodeValue::LetElse(binding) => {
11243
            if let subjectTy = typeFor(checker.resolver, binding.pattern.scrutinee);
11244
                isLinear(subjectTy)
11245
            {
11246
                throw emitError(
11247
                    checker.resolver,
11248
                    binding.pattern.scrutinee,
11249
                    ErrorKind::LinearPartialMove,
11250
                );
11251
            }
11252
            try checkLinearNode(
11253
                checker,
11254
                env,
11255
                binding.pattern.scrutinee,
11256
                patternSubjectUse(checker.resolver, binding.pattern.scrutinee),
11257
            );
11258
            let base = *env;
11259
            let mut guardedEnv = base;
11260
            if let guard = binding.pattern.guard {
11261
                try checkLinearNode(checker, &mut guardedEnv, guard, LinearUse::Consume);
11262
            }
11263
            let mut successEnv = guardedEnv;
11264
            try addLinearPatternBindings(
11265
                checker,
11266
                &mut successEnv,
11267
                binding.pattern.pattern,
11268
            );
11269
            let mut fallbackEnv = base;
11270
            try checkLinearNode(
11271
                checker,
11272
                &mut fallbackEnv,
11273
                binding.elseBranch,
11274
                LinearUse::Consume,
11275
            );
11276
            if binding.pattern.guard <> nil {
11277
                let mut guardFallbackEnv = guardedEnv;
11278
                try checkLinearNode(
11279
                    checker,
11280
                    &mut guardFallbackEnv,
11281
                    binding.elseBranch,
11282
                    LinearUse::Consume,
11283
                );
11284
                let previous = fallbackEnv;
11285
                try joinLinearBranches(
11286
                    checker,
11287
                    &mut fallbackEnv,
11288
                    &previous,
11289
                    &guardFallbackEnv,
11290
                    binding.elseBranch,
11291
                );
11292
            }
11293
            if let case ast::PatternKind::Binding = binding.pattern.kind {
11294
                try addLinearPatternBindings(
11295
                    checker,
11296
                    &mut fallbackEnv,
11297
                    binding.pattern.pattern,
11298
                );
11299
            }
11300
            try joinLinearBranches(checker, env, &successEnv, &fallbackEnv, node);
11301
        }
11302
        case ast::NodeValue::Match(matchExpr) => {
11303
            try checkLinearMatch(checker, env, node, matchExpr);
11304
        }
11305
        case ast::NodeValue::Try(tryExpr) => {
11306
            try checkLinearNode(checker, env, tryExpr.expr, usage);
11307
            let success = *env;
11308
            if let resultTy = typeFor(checker.resolver, tryExpr.expr); resultTy == Type::Never {
11309
                if not tryExpr.returnsOptional and (tryExpr.catches.len > 0 or tryExpr.shouldPanic) {
11310
                    set env.terminated = true;
11311
                }
11312
            }
11313
            for catchNode in tryExpr.catches {
11314
                let case ast::NodeValue::CatchClause(catchClause) = catchNode.value
11315
                    else panic "checkLinearNode: expected catch";
11316
                let mut branch = success;
11317
                let start = branch.len;
11318
                if let binding = catchClause.binding {
11319
                    try addLinearBinding(checker, &mut branch, binding);
11320
                }
11321
                try checkLinearNode(checker, &mut branch, catchClause.body, usage);
11322
                try finishLinearScope(checker, &mut branch, start);
11323
                let previous = *env;
11324
                try joinLinearBranches(checker, env, &previous, &branch, node);
11325
            }
11326
        }
11327
        case ast::NodeValue::While(_), ast::NodeValue::WhileLet(_),
11328
             ast::NodeValue::For(_), ast::NodeValue::Loop { .. } =>
11329
            try checkLinearLoop(checker, env, node),
11330
        case ast::NodeValue::Break => {
11331
            assert checker.loopDepth > 0, "linear loop control outside loop";
11332
            let start = checker.loopMarks[checker.loopDepth - 1];
11333
            try finishLinearScope(checker, env, start);
11334
            try checkLinearLoopBreak(checker, env, node);
11335
            set env.terminated = true;
11336
        }
11337
        case ast::NodeValue::Continue => {
11338
            assert checker.loopDepth > 0, "linear loop control outside loop";
11339
            let start = checker.loopMarks[checker.loopDepth - 1];
11340
            try finishLinearScope(checker, env, start);
11341
            try checkLinearLoopBackEdge(checker, env, node);
11342
            set env.terminated = true;
11343
        }
11344
        case ast::NodeValue::Return { value } => {
11345
            if let expr = value {
11346
                try checkLinearNode(checker, env, expr, LinearUse::Consume);
11347
            }
11348
            try finishLinearExit(checker, env);
11349
        }
11350
        case ast::NodeValue::Throw { expr } => {
11351
            try checkLinearNode(checker, env, expr, LinearUse::Consume);
11352
            try finishLinearExit(checker, env);
11353
        }
11354
        case ast::NodeValue::Panic { message } => {
11355
            if let expr = message {
11356
                try checkLinearNode(checker, env, expr, LinearUse::Consume);
11357
            }
11358
            set env.terminated = true;
11359
        }
11360
        case ast::NodeValue::Assert { condition, message } => {
11361
            try checkLinearNode(checker, env, condition, LinearUse::Consume);
11362
            if let expr = message {
11363
                try checkLinearNode(checker, env, expr, LinearUse::Consume);
11364
            }
11365
        }
11366
        else => {}
11367
    }
11368
}
11369
11370
/// Check exact-use ownership for one resolved function.
11371
unsafe fn checkLinearFn 'arena (
11372
    self: &mut Resolver 'arena,
11373
    receiver: ?*ast::Node,
11374
    params: *[*ast::Node],
11375
    body: *ast::Node,
11376
) throws (ResolveError) {
11377
    try resolveNominalApplications(self, body);
11378
    let regions = self.regionScope;
11379
    let resolved: 'checking = &mut *self where 'arena: 'checking in {
11380
        let mut checker = LinearChecker 'arena 'checking {
11381
            resolver: resolved,
11382
            regional: undefined,
11383
            regionalLen: 0,
11384
            regions,
11385
            loopBackLoans: undefined,
11386
            loopExitLoans: undefined,
11387
            loopRegions: undefined,
11388
            loans: undefined,
11389
            loanLen: 0,
11390
            locals: undefined,
11391
            localLen: 0,
11392
            loopMarks: undefined,
11393
            loopAvailable: undefined,
11394
            loopExitAvailable: undefined,
11395
            loopHasNaturalExit: undefined,
11396
            loopBreakSeen: undefined,
11397
            loopDepth: 0,
11398
        };
11399
        let mut env = LinearEnv {
11400
            regionalLoans: 0,
11401
            symbols: undefined,
11402
            available: 0,
11403
            len: 0,
11404
            terminated: false,
11405
        };
11406
        if let receiverNode = receiver {
11407
            try addLinearBinding(&mut checker, &mut env, receiverNode);
11408
        }
11409
        for paramNode in params {
11410
            let case ast::NodeValue::FnParam(_) = paramNode.value
11411
                else panic "checkLinearFn: expected parameter";
11412
            try addLinearBinding(&mut checker, &mut env, paramNode);
11413
        }
11414
        try checkLinearNode(&mut checker, &mut env, body, LinearUse::Discard);
11415
        try finishLinearScope(&mut checker, &mut env, 0);
11416
    }
11417
}
11418
11419
/// Analyze module definitions. This pass analyzes function bodies, recursing into sub-modules.
11420
unsafe fn resolveModuleDefs 'arena (self: &mut Resolver 'arena, block: &ast::Block) throws (ResolveError) {
11421
    for stmt in block.statements {
11422
        try resolveNominalApplications(self, stmt);
11423
        try visitDef(self, stmt);
11424
        try resolveNominalApplications(self, stmt);
11425
    }
11426
}
11427
11428
/// Resolve all packages.
11429
/// The graph must outlive later uses of the resolver.
11430
export unsafe fn resolve 'arena (self: &mut Resolver 'arena, graph: &module::ModuleGraph, packages: &[Pkg]) -> Diagnostics throws (ResolveError) {
11431
    set self.moduleGraph = graph as *unsafe module::ModuleGraph;
11432
11433
    // 1. Bind all package roots to enable cross-package references.
11434
    for i in 0..packages.len {
11435
        let pkg = packages[i];
11436
        // Enter a new scope for the module.
11437
        let enter = enterModuleScope(self, pkg.rootAst, pkg.rootEntry);
11438
        // Bind the package root module name in the global package scope.
11439
        let scope = self.pkgScope;
11440
        try bindModuleIdent(self, pkg.rootEntry, enter.newScope, pkg.rootAst, 0, scope);
11441
11442
        exitModuleScope(self, enter);
11443
    }
11444
    // 2. Resolve each package's contents.
11445
    for i in 0..packages.len {
11446
        let pkg = packages[i];
11447
        let diags = try resolvePackage(self, pkg.rootEntry, pkg.rootAst);
11448
        if not success(&diags) {
11449
            return diags;
11450
        }
11451
    }
11452
    return diagnostics(self);
11453
}
11454
11455
/// Resolve a package.
11456
unsafe fn resolvePackage 'arena (self: &mut Resolver 'arena, rootEntry: *module::ModuleEntry, node: *ast::Node) -> Diagnostics throws (ResolveError) {
11457
    let rootId = rootEntry.id;
11458
    let scope = self.moduleScopes[rootId as u32]
11459
        else panic "resolvePackage: module scope not found";
11460
11461
    // Set up the module scope for this package.
11462
    set self.scope = scope;
11463
    set self.currentMod = rootId;
11464
11465
    let case ast::NodeValue::Block(block) = node.value
11466
        else panic "resolvePackage: expected block for module root";
11467
11468
    // Module graph analysis phase: bind all module name symbols and scopes.
11469
    try resolveModuleGraph(self, &block) catch {
11470
        assert self.errors.len > 0, "resolvePackage: failure should have diagnostics";
11471
        return diagnostics(self);
11472
    };
11473
11474
    // Declaration phase: bind all names and analyze top-level declarations.
11475
    try resolveModuleDecls(self, &block) catch {
11476
        assert self.errors.len > 0, "resolvePackage: failure should have diagnostics";
11477
    };
11478
    if self.errors.len > 0 {
11479
        return diagnostics(self);
11480
    }
11481
11482
    // Definition phase: analyze function bodies and sub-module definitions.
11483
    try resolveModuleDefs(self, &block) catch {
11484
        assert self.errors.len > 0, "resolvePackage: failure should have diagnostics";
11485
    };
11486
    setNodeType(self, node, Type::Void);
11487
11488
    return diagnostics(self);
11489
}