lib/std/lang/resolver.rad 407.8 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 = 768;
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 generic parameters on one declaration.
51
export constant MAX_GENERIC_PARAMS: u32 = 8;
52
/// Maximum explicit specialization roots in one package.
53
export constant MAX_GENERIC_ROOTS: u32 = 256;
54
/// Maximum canonical data and function specializations in one package.
55
export constant MAX_GENERIC_SPECIALIZATIONS: u32 = 512;
56
/// Maximum expanding generic function dependency depth.
57
export constant MAX_GENERIC_SPECIALIZATION_DEPTH: u16 = 32;
58
59
/// Resolution state for a trait signature table.
60
export union TraitState {
61
    Queued,
62
    Resolving,
63
    Complete,
64
}
65
66
/// Trait definition stored in the resolver.
67
export record TraitType {
68
    /// Trait name.
69
    name: *[u8],
70
    /// Module-local identity used by semantic tables.
71
    moduleId: u16,
72
    nodeId: u32,
73
    /// Method signatures, including from supertraits.
74
    methods: *mut [TraitMethod],
75
    /// Supertraits that must also be implemented.
76
    supertraits: *mut [*TraitType],
77
    /// Rigid `Self` type used by static signatures.
78
    selfType: *GenericParamType,
79
    /// Whether signature resolution has started or completed.
80
    state: TraitState,
81
    /// Whether every vtable-exposed method is object-safe.
82
    objectSafe: bool,
83
}
84
85
/// A single method signature within a trait.
86
export record TraitMethod {
87
    /// Method name.
88
    name: *[u8],
89
    /// Function type for the method, excluding the receiver.
90
    fnType: *FnType,
91
    /// Whether the receiver is mutable.
92
    mutable: bool,
93
    /// Pointer-like class used by the receiver.
94
    receiverClass: types::PointerClass,
95
    /// Trait that originally declared this method.
96
    owner: *TraitType,
97
    /// V-table slot index.
98
    index: u32,
99
}
100
101
/// An entry in the trait instance registry.
102
export record InstanceEntry {
103
    /// Trait type descriptor.
104
    traitType: *TraitType,
105
    /// Concrete type that implements the trait.
106
    concreteType: Type,
107
    /// Module where this instance was declared.
108
    moduleId: u16,
109
    /// Method symbols for each trait method, in declaration order.
110
    methods: *mut [*mut Symbol],
111
}
112
113
/// An entry in the method registry.
114
export record MethodEntry {
115
    /// Concrete type that owns the method.
116
    concreteType: Type,
117
    /// Method name.
118
    name: *[u8],
119
    /// Function type excluding the receiver.
120
    fnType: *FnType,
121
    /// Whether the receiver is mutable.
122
    mutable: bool,
123
    /// Pointer-like class used by the receiver.
124
    receiverClass: types::PointerClass,
125
    /// Symbol for the method.
126
    symbol: *mut Symbol,
127
}
128
129
/// Identifier for the synthetic `len` field.
130
export constant LEN_FIELD: *[u8] = "len";
131
/// Identifier for the synthetic `ptr` field.
132
export constant PTR_FIELD: *[u8] = "ptr";
133
/// Identifier for the synthetic `cap` field.
134
export constant CAP_FIELD: *[u8] = "cap";
135
136
/// Maximum `u16` value.
137
constant U16_MAX: u16 = 0xFFFF;
138
/// Maximum `u8` value.
139
constant U8_MAX: u16 = 0xFF;
140
141
/// Minimum `i8` value.
142
constant I8_MIN: i32 = -128;
143
/// Maximum `i8` value.
144
constant I8_MAX: i32 = 127;
145
/// Minimum `i16` value.
146
constant I16_MIN: i32 = -32768;
147
/// Maximum `i16` value.
148
constant I16_MAX: i32 = 32767;
149
150
/// Minimum `i32` value.
151
constant I32_MIN: i32 = -2147483648;
152
/// Maximum `i32` value.
153
constant I32_MAX: i32 = 2147483647;
154
/// Minimum `i64` value: -(2^63).
155
constant I64_MIN: i64 = -9223372036854775808;
156
/// Maximum `i64` value: 2^63 - 1.
157
constant I64_MAX: i64 = 9223372036854775807;
158
159
/// Size of a pointer in bytes.
160
export constant PTR_SIZE: u32 = 8;
161
162
/// Information about a record or tuple field.
163
export record RecordField {
164
    /// Field name, `nil` for positional fields.
165
    name: ?*[u8],
166
    /// Field type.
167
    fieldType: Type,
168
    /// Byte offset from the start of the record.
169
    offset: i32,
170
}
171
172
/// Information about a union variant.
173
record UnionVariant {
174
    name: *[u8],
175
    valueType: Type,
176
    symbol: *mut Symbol,
177
}
178
179
/// Array type payload.
180
export record ArrayType {
181
    item: *Type,
182
    length: u32,
183
}
184
185
/// Anonymous record whose field layout depends on rigid parameters.
186
export record GenericRecordType {
187
    fields: *[RecordField],
188
    labeled: bool,
189
}
190
191
/// Record nominal type.
192
export record RecordType {
193
    fields: *[RecordField],
194
    labeled: bool,
195
    /// Cached layout.
196
    layout: Layout,
197
    /// Whether the declaration explicitly carries the `Linear` marker.
198
    declaredLinear: bool,
199
}
200
201
/// Union nominal type.
202
export record UnionType {
203
    variants: *[UnionVariant],
204
    /// Cached layout.
205
    layout: Layout,
206
    /// Cached payload offset within the union aggregate.
207
    valOffset: u32,
208
    /// If all variants have void payloads.
209
    isAllVoid: bool,
210
    /// Whether the declaration explicitly carries the `Linear` marker.
211
    declaredLinear: bool,
212
}
213
214
/// Metadata for user-defined types.
215
export union NominalType {
216
    /// Placeholder for a type that hasn't been fully resolved yet.
217
    /// Stores the declaration node for lazy resolution.
218
    Placeholder(*ast::Node),
219
    Record(RecordType),
220
    Union(UnionType),
221
}
222
223
/// Coercion plan, when coercion from one type to another.
224
export union Coercion {
225
    /// No coercion, eg. `T -> T`.
226
    Identity,
227
    /// Eg. `u8 -> i32`. Stores both source and target types for lowering.
228
    NumericCast { from: Type, to: Type },
229
    /// Eg. `T -> ?T`. Stores the inner value type.
230
    OptionalLift(Type),
231
    /// Wrap return value in success variant of result type.
232
    ResultWrap,
233
    /// Coerce a concrete pointer to a trait object.
234
    TraitObject {
235
        /// Trait type information.
236
        traitInfo: *TraitType,
237
        /// Instance entry for v-table lookup.
238
        inst: *InstanceEntry,
239
    },
240
}
241
242
/// Result of resolving a module path.
243
record ResolvedModule {
244
    /// Module entry in the graph.
245
    entry: *module::ModuleEntry,
246
    /// Scope containing the module's declarations.
247
    scope: *mut Scope,
248
}
249
250
/// Type layout.
251
export record Layout {
252
    /// Size in bytes.
253
    size: u32,
254
    /// Alignment in bytes.
255
    alignment: u32,
256
}
257
258
/// Computed union layout parameters.
259
record UnionLayoutInfo {
260
    layout: Layout,
261
    valOffset: u32,
262
    isAllVoid: bool,
263
}
264
265
/// Pre-computed metadata for slice range expressions.
266
/// Used by the lowerer.
267
export record SliceRangeInfo {
268
    /// Element type of the resulting slice.
269
    itemType: *Type,
270
    /// Whether the resulting slice is mutable.
271
    mutable: bool,
272
    /// Static capacity if container is an array.
273
    capacity: ?u32,
274
}
275
276
/// Pre-computed metadata for `for` loop iteration.
277
/// Used by the lowerer to avoid re-analyzing the iterable type.
278
export union ForLoopInfo {
279
    /// Iterating over a range expression (e.g., `for i in 0..n`).
280
    Range {
281
        valType: *Type,
282
        range: ast::Range,
283
        bindingName: ?*[u8],
284
        indexName: ?*[u8]
285
    },
286
    /// Iterating over an array or slice. For arrays, the length field is set.
287
    Collection {
288
        elemType: *Type,
289
        length: ?u32,
290
        bindingName: ?*[u8],
291
        indexName: ?*[u8]
292
    },
293
}
294
295
/// A rigid type parameter belonging to one generic declaration.
296
export record GenericParamType {
297
    /// Declaration that owns the parameter.
298
    owner: *ast::Node,
299
    /// Parameter declaration node.
300
    node: *ast::Node,
301
    /// Parameter name.
302
    name: *[u8],
303
    /// Position in the declaration's ordered parameter list.
304
    index: u32,
305
    /// Resolved trait bounds.
306
    bounds: *[*TraitType],
307
    /// Shared usage flag, mutable through symbol references.
308
    used: *mut bool,
309
    /// Declared integer type for a constant parameter, or `nil` for a type parameter.
310
    constType: ?*Type,
311
}
312
313
/// Resolved function signature details.
314
export record FnType {
315
    paramTypes: *[*Type],
316
    returnType: *Type,
317
    throwList: *[*Type],
318
    /// Whether calling this function requires an unsafe context.
319
    isUnsafe: bool,
320
    localCount: u32,
321
}
322
323
/// Resolved, declaration-scoped generic metadata.
324
export record GenericTemplate {
325
    /// Declaration that owns this template.
326
    decl: *ast::Node,
327
    /// Ordered rigid type parameters.
328
    params: *[*GenericParamType],
329
    /// Symbolic function signature, for function templates.
330
    signature: ?*FnType,
331
    /// Symbolic field or variant types, in declaration order.
332
    members: *[*Type],
333
    /// Whether the declaration explicitly carries the `Linear` marker.
334
    declaredLinear: bool,
335
    moduleId: ?u16,
336
    /// Whether a generic function body has already been checked.
337
    bodyResolved: bool,
338
    /// Number of body-analysis entries, retained to enforce check-once behavior.
339
    bodyChecks: u8,
340
}
341
342
/// Canonical concrete specialization of a generic record or union.
343
export record GenericDataSpecialization {
344
    /// Template symbol whose declaration is specialized.
345
    template: *mut Symbol,
346
    /// Ordered, interned concrete type arguments.
347
    args: *[*Type],
348
    /// Ordinary nominal type produced for this application.
349
    nominal: *mut NominalType,
350
    /// Whether an explicit `instantiate` declaration requested this type.
351
    rooted: *mut bool,
352
    /// First concrete application site, used for root diagnostics.
353
    site: *ast::Node,
354
}
355
356
/// Worklist state for a concrete generic function body.
357
export union GenericFnState {
358
    Queued,
359
    Lowering,
360
    Complete,
361
}
362
363
/// Canonical concrete specialization of a generic free function.
364
export record GenericFnSpecialization {
365
    /// Template symbol whose body is lowered.
366
    template: *mut Symbol,
367
    /// Ordered, interned concrete type arguments.
368
    args: *[*Type],
369
    /// Substituted concrete function signature.
370
    fnType: *FnType,
371
    /// First explicit instantiation site.
372
    site: *ast::Node,
373
    /// Dependency-closure state.
374
    state: GenericFnState,
375
    /// Distance from an explicit root, used to bound expanding recursion.
376
    depth: u16,
377
}
378
379
/// Linked cache entry for generic function specializations.
380
export record GenericFnSpecializationNode {
381
    specialization: GenericFnSpecialization,
382
    next: ?*mut GenericFnSpecializationNode,
383
}
384
385
/// A generic call retained in a checked symbolic function body.
386
export record GenericFnDependency {
387
    caller: ?*mut Symbol,
388
    callee: *mut Symbol,
389
    args: *[*Type],
390
    site: *ast::Node,
391
    next: ?*GenericFnDependency,
392
}
393
394
/// Concrete call selected for one symbolic edge in one caller specialization.
395
export record GenericFnDependencyResolution {
396
    dependency: *GenericFnDependency,
397
    caller: *GenericFnSpecialization,
398
    callee: *GenericFnSpecialization,
399
    next: ?*GenericFnDependencyResolution,
400
}
401
402
/// Linked cache entry for generic data specializations.
403
record GenericDataSpecializationNode {
404
    specialization: GenericDataSpecialization,
405
    next: ?*GenericDataSpecializationNode,
406
}
407
408
/// Sparse generic metadata entry, allocated only for template symbols.
409
record GenericTemplateNode {
410
    symbol: *mut Symbol,
411
    template: GenericTemplate,
412
    next: ?*mut GenericTemplateNode,
413
}
414
415
/// Ordered replacement types for rigid parameters.
416
export record Substitution {
417
    params: *[*GenericParamType],
418
    args: *[*Type],
419
}
420
421
/// Symbolic application of a generic data template inside another template.
422
export record GenericDataApplyType {
423
    template: *mut Symbol,
424
    args: *[*Type],
425
    site: *ast::Node,
426
}
427
428
/// Pointer-like address payload.
429
export record PointerType {
430
    /// Ownership and safety class.
431
    class: types::PointerClass,
432
    /// Pointer target type.
433
    target: *Type,
434
    /// Whether the pointer is mutable.
435
    mutable: bool,
436
}
437
438
/// Pointer-like slice payload.
439
export record SliceType {
440
    /// Ownership and safety class.
441
    class: types::PointerClass,
442
    /// Slice element type.
443
    item: *Type,
444
    /// Whether the slice is mutable.
445
    mutable: bool,
446
}
447
448
/// Erased pointer-like type payload.
449
export record TraitObjectType {
450
    /// Ownership and safety class.
451
    class: types::PointerClass,
452
    /// Trait definition.
453
    traitInfo: *TraitType,
454
    /// Whether the pointer is mutable.
455
    mutable: bool,
456
}
457
458
/// Describes a type computed during semantic analysis.
459
export union Type {
460
    /// A type that couldn't be decided.
461
    Unknown,
462
    /// Types only used during inference.
463
    Nil, Undefined, Int,
464
    /// Primitive types.
465
    Void, Opaque, Never, Bool,
466
    /// Integer types.
467
    U8, U16, U32, U64, I8, I16, I32, I64,
468
    /// Range types, eg. `start..end`.
469
    Range {
470
        start: ?*Type,
471
        end: ?*Type,
472
    },
473
    /// Pointer-like address.
474
    Pointer(PointerType),
475
    /// Pointer-like slice.
476
    Slice(SliceType),
477
    /// Eg. `[i32; 32]`.
478
    Array(ArrayType),
479
    /// Array type whose length depends on a rigid constant parameter.
480
    GenericArray {
481
        item: *Type,
482
        length: *ast::Node,
483
    },
484
    /// Rigid integer constant parameter within a generic declaration.
485
    ConstParameter(*GenericParamType),
486
    /// Canonical typed integer generic argument.
487
    ConstArgument {
488
        type: *Type,
489
        value: ConstInt,
490
    },
491
    /// Symbolic integer expression awaiting constant-parameter substitution.
492
    GenericConstExpr {
493
        type: *Type,
494
        expr: *ast::Node,
495
    },
496
    /// Eg. `?T`.
497
    Optional(*Type),
498
    /// Eg. `fn id(i32) -> i32`.
499
    Fn(*FnType),
500
    /// Named, ie. user-defined types, includes union variants.
501
    Nominal(*NominalType),
502
    /// Rigid type parameter within a generic declaration.
503
    Parameter(*GenericParamType),
504
    /// Anonymous record awaiting substitution before layout.
505
    GenericRecord(*GenericRecordType),
506
    /// Generic data application awaiting substitution of its arguments.
507
    GenericDataApply(*GenericDataApplyType),
508
    /// An erased pointer-like type with a v-table.
509
    TraitObject(TraitObjectType),
510
}
511
512
/// Structured diagnostic payload for type mismatches.
513
export record TypeMismatch {
514
    expected: Type,
515
    actual: Type,
516
}
517
518
/// Structured diagnostic payload for invalid `as` casts.
519
export record InvalidAsCast {
520
    from: Type,
521
    to: Type,
522
}
523
524
/// Diagnostic payload for argument count mismatches.
525
export record CountMismatch {
526
    expected: u32,
527
    actual: u32,
528
}
529
530
/// Detailed payload attached to a symbol, specialized per symbol kind.
531
export union SymbolData {
532
    /// Payload describing mutable bindings like variables or functions.
533
    Value {
534
        /// Whether the binding permits mutation.
535
        mutable: bool,
536
        /// Custom alignment requirement, or 0 for default.
537
        alignment: u32,
538
        /// Resolved type associated with the value.
539
        type: Type,
540
        /// Whether the variable's address is taken anywhere (via `&` or `&mut`).
541
        /// Used by the lowerer to allocate a stack slot eagerly.
542
        addressTaken: bool,
543
    },
544
    /// Payload describing constants.
545
    Constant {
546
        /// Resolved type associated with the value.
547
        type: Type,
548
        /// Constant value, if any.
549
        value: ?ConstValue,
550
    },
551
    /// Payload describing union variants and the union type they instantiate.
552
    Variant {
553
        /// Variant payload type.
554
        type: Type,
555
        /// Union declaration.
556
        decl: *ast::Node,
557
        /// Variant ordinal in declaration order.
558
        ordinal: u32,
559
        /// Variant index within the union.
560
        index: u32,
561
    },
562
    /// Module reference.
563
    Module {
564
        /// Module entry in the graph.
565
        entry: *module::ModuleEntry,
566
        /// Module scope.
567
        scope: *mut Scope,
568
    },
569
    /// Payload describing type symbols with their resolved type.
570
    Type(*mut NominalType),
571
    /// Rigid generic type parameter.
572
    TypeParameter(*GenericParamType),
573
    /// Rigid generic integer constant parameter.
574
    ConstParameter(*GenericParamType),
575
    /// Trait symbol.
576
    Trait(*mut TraitType),
577
}
578
579
/// Resolved symbol allocated during semantic analysis.
580
export record Symbol {
581
    /// Symbol name in source code.
582
    name: *[u8],
583
    /// Data associated with the symbol.
584
    data: SymbolData,
585
    /// Bitset of attributes applied to the declaration.
586
    attrs: u32,
587
    /// AST node that introduced the symbol.
588
    node: *ast::Node,
589
    /// Module ID this symbol belongs to. Only for module-level symbols.
590
    moduleId: ?u16,
591
}
592
593
/// Integer constant payload.
594
export record ConstInt {
595
    /// Absolute magnitude of the value.
596
    magnitude: u64,
597
    /// Bit width of the integer.
598
    bits: u8,
599
    /// Whether the integer is signed.
600
    signed: bool,
601
    /// Whether the value is negative (only valid when `signed` is true).
602
    negative: bool,
603
}
604
605
/// Constant value recorded for literal nodes.
606
export union ConstValue {
607
    Bool(bool),
608
    Char(u8),
609
    String(*[u8]),
610
    Int(ConstInt),
611
}
612
613
/// Integer range metadata for primitive integer types.
614
union IntegerRange {
615
    Signed {
616
        bits: u8,
617
        min: i64,
618
        max: i64,
619
        lim: u64,
620
    },
621
    Unsigned {
622
        bits: u8,
623
        max: u64,
624
    },
625
}
626
627
/// Diagnostic emitted by the analyzer.
628
export record Error {
629
    /// Error category.
630
    kind: ErrorKind,
631
    /// Node associated with the error, if known.
632
    node: ?*ast::Node,
633
    /// Module ID where this error occurred.
634
    moduleId: u16,
635
}
636
637
/// High-level classification for semantic diagnostics.
638
export union ErrorKind {
639
    /// Identifier declared more than once in the same scope.
640
    DuplicateBinding(*[u8]),
641
    /// Identifier referenced before it was declared.
642
    UnresolvedSymbol(*[u8]),
643
    /// Attempted to assign to an immutable binding.
644
    ImmutableBinding,
645
    /// Expected a compile-time constant expression.
646
    ConstExprRequired,
647
    /// Symbol arena exhausted while binding identifiers.
648
    SymbolOverflow,
649
    /// Expression has the wrong type.
650
    TypeMismatch(TypeMismatch),
651
    /// Numeric literal does not fit within the required range.
652
    NumericLiteralOverflow,
653
    /// Record literal omitted a required field.
654
    RecordFieldMissing(*[u8]),
655
    /// Record literal referenced a field that does not exist.
656
    RecordFieldUnknown(*[u8]),
657
    /// Brace syntax used on unlabeled record.
658
    RecordFieldStyleMismatch,
659
    /// Record literal supplied the wrong number of fields.
660
    RecordFieldCountMismatch(CountMismatch),
661
    /// Record literal fields not in declaration order.
662
    RecordFieldOutOfOrder { field: *[u8], prev: *[u8] },
663
    /// Function call supplied the wrong number of arguments.
664
    FnArgCountMismatch(CountMismatch),
665
    /// Function throws list has the wrong number of types.
666
    FnThrowCountMismatch(CountMismatch),
667
    /// Expected an identifier node.
668
    ExpectedIdentifier,
669
    /// Expected any optional type.
670
    ExpectedOptional,
671
    /// Expected a numeric type.
672
    ExpectedNumeric,
673
    /// Expected a pointer type.
674
    ExpectedPointer,
675
    /// Expected a record type.
676
    ExpectedRecord,
677
    /// Expected an array or slice value.
678
    ExpectedIndexable,
679
    /// Expected an iterable (array, slice, or range) for a `for` loop.
680
    ExpectedIterable,
681
    /// Invalid `as` cast between the provided types.
682
    InvalidAsCast(InvalidAsCast),
683
    /// Invalid alignment value specified.
684
    InvalidAlignmentValue(u32),
685
    /// Invalid module path.
686
    InvalidModulePath,
687
    /// Invalid identifier.
688
    InvalidIdentifier(*ast::Node),
689
    /// Invalid scope access.
690
    InvalidScopeAccess,
691
    /// Referenced an unknown array field.
692
    ArrayFieldUnknown(*[u8]),
693
    /// Referenced an unknown slice field.
694
    SliceFieldUnknown(*[u8]),
695
    /// Array slicing without taking an address.
696
    SliceRequiresAddress,
697
    /// Slice bounds exceed array length.
698
    SliceRangeOutOfBounds,
699
    /// Unexpected `return` statement.
700
    UnexpectedReturn,
701
    /// Unexpected module name.
702
    UnexpectedModuleName,
703
    /// Unexpected node.
704
    UnexpectedNode(*ast::Node),
705
    /// Function with non-void return type falls through without returning.
706
    FnMissingReturn,
707
    /// Function is missing a body.
708
    FnMissingBody,
709
    /// Function body is not expected.
710
    FnUnexpectedBody,
711
    /// Intrinsic function must not have a body.
712
    IntrinsicUnexpectedBody,
713
    /// Encountered loop control outside of a loop construct.
714
    InvalidLoopControl,
715
    /// `try` used when the enclosing function does not declare throws.
716
    TryRequiresThrows,
717
    /// `try` used to propagate an error not declared by the enclosing function.
718
    TryIncompatibleError,
719
    /// `throw` used when the enclosing function does not declare throws.
720
    ThrowRequiresThrows,
721
    /// `throw` used with an error type not declared by the enclosing function.
722
    ThrowIncompatibleError,
723
    /// `try` applied to an expression that cannot throw.
724
    TryNonThrowing,
725
    /// Inferred catch binding used with multi-error callee.
726
    TryCatchMultiError,
727
    /// Duplicate error type in typed catch clauses.
728
    TryCatchDuplicateType,
729
    /// Typed catch clauses do not cover all error types.
730
    TryCatchNonExhaustive,
731
    /// Called a fallible function without using `try`.
732
    MissingTry,
733
    /// Cannot use opaque type in this context.
734
    OpaqueTypeNotAllowed,
735
    /// Cannot dereference pointer to opaque type.
736
    OpaqueTypeDeref,
737
    /// Cannot perform pointer arithmetic on opaque pointer.
738
    OpaquePointerArithmetic,
739
    /// Cannot infer type from context.
740
    CannotInferType,
741
    /// Cannot assign a void value to a variable.
742
    CannotAssignVoid,
743
    /// `default` attribute used on a non-function declaration.
744
    DefaultAttrOnlyOnFn,
745
    /// Union variant requires a payload but none was provided.
746
    UnionVariantPayloadMissing(*[u8]),
747
    /// Union variant does not expect a payload but one was provided.
748
    UnionVariantPayloadUnexpected(*[u8]),
749
    /// `match` on a union omits a variant without a `default` case.
750
    UnionMatchNonExhaustive(*[u8]),
751
    /// `match` on an optional is missing a value case.
752
    OptionalMatchMissingValue,
753
    /// `match` on an optional is missing a nil case.
754
    OptionalMatchMissingNil,
755
    /// `match` on a bool is missing a case (true or false).
756
    BoolMatchMissing(bool),
757
    /// `match` on a non-union type is missing a catch-all.
758
    MatchNonExhaustive,
759
    /// `match` has more than one catch-all prongs.
760
    DuplicateCatchAll,
761
    /// `match` has a duplicate case pattern.
762
    DuplicateMatchPattern,
763
    /// `match` has an unreachable `else`: all cases are already handled.
764
    UnreachableElse,
765
    /// Builtin called with wrong number of arguments.
766
    BuiltinArgCountMismatch(CountMismatch),
767
    /// Instance method receiver mutability does not match the trait declaration.
768
    ReceiverMutabilityMismatch,
769
    /// Duplicate instance declaration for the same (trait, type) pair.
770
    DuplicateInstance,
771
    /// Instance declaration is missing a required trait method.
772
    MissingTraitMethod(*[u8]),
773
    /// Subtrait instance attempts to override an inherited method.
774
    InheritedTraitMethod(*[u8]),
775
    /// Trait name used as a value expression.
776
    UnexpectedTraitName,
777
    /// Trait method receiver does not point to the declaring trait.
778
    TraitReceiverMismatch,
779
    /// A trait mentioning `Self` outside its receiver cannot form an object.
780
    TraitNotObjectSafe,
781
    /// Supertrait declarations form a cycle.
782
    TraitInheritanceCycle,
783
    /// An instance target is not a supported concrete type.
784
    InvalidInstanceTarget,
785
    /// Trait declaration and instance disagree about unsafe call requirements.
786
    TraitMethodSafetyMismatch,
787
    /// Function declaration has too many parameters.
788
    FnParamOverflow(CountMismatch),
789
    /// Function declaration has too many throws.
790
    FnThrowOverflow(CountMismatch),
791
    /// Trait declaration has too many methods.
792
    TraitMethodOverflow(CountMismatch),
793
    /// Instance declaration is missing a required supertrait instance.
794
    MissingSupertraitInstance(*[u8]),
795
    /// Linear binding was consumed more than once.
796
    LinearUseAfterConsume(*[u8]),
797
    /// Linear binding remains available at an exit.
798
    LinearNotConsumed(*[u8]),
799
    /// A case-pattern `let-else` fallback must terminate control flow.
800
    LinearLetElseMustTerminate,
801
    /// Branches disagree about a linear binding's state.
802
    LinearBranchMismatch(*[u8]),
803
    /// A linear field cannot be moved independently.
804
    LinearPartialMove,
805
    /// A linear value cannot be discarded.
806
    LinearDiscard,
807
    /// Assignment would overwrite a live linear value.
808
    LinearOverwrite,
809
    /// `undefined` cannot initialize a linear type.
810
    LinearUndefined,
811
    /// A reference appears in a storable or escaping position.
812
    InvalidRefPosition,
813
    /// A reference cannot be bound to a local.
814
    RefBinding,
815
    /// Call arguments contain overlapping incompatible loans.
816
    BorrowConflict(*[u8]),
817
    /// Unsafe pointer operation outside an `unsafe` declaration.
818
    UnsafeOperation,
819
    /// Safe code cannot call an `unsafe` function.
820
    UnsafeCall,
821
    /// A syntax node is not valid in a generic context.
822
    GenericUnsupported,
823
    /// A generic bound did not name a trait.
824
    GenericBoundNotTrait,
825
    /// A constant parameter type is not a concrete integer type.
826
    GenericConstUnsupported,
827
    /// An attribute cannot be applied to a generic function.
828
    GenericFnAttribute,
829
    /// Generic function declarations must be at module scope.
830
    GenericFnNested,
831
    /// A type parameter does not affect its function.
832
    GenericFnUnusedParameter(*[u8]),
833
    /// More than one bound exposes the selected method name.
834
    GenericBoundAmbiguous(*[u8]),
835
    /// A rigid parameter was used where a concrete layout is required.
836
    GenericLayoutRequired,
837
    /// A concrete generic specialization has infinitely recursive layout.
838
    GenericRecursiveLayout,
839
    /// A function specialization targeted a non-function declaration.
840
    GenericFunctionExpected,
841
    /// A concrete type argument does not satisfy a declared trait bound.
842
    GenericBoundUnsatisfied(*[u8]),
843
    /// A generic function application has no explicit instantiation root.
844
    GenericFunctionInstantiationRequired,
845
    /// A generic call graph expands beyond the specialization bound.
846
    GenericSpecializationChain,
847
    /// Generic argument inference did not determine every parameter.
848
    GenericInferenceIncomplete,
849
    /// Generic argument inference found incompatible evidence.
850
    GenericInferenceConflict,
851
    /// A generic declaration was named without required arguments.
852
    GenericArgumentsRequired,
853
    /// A concrete application is not covered by an explicit instantiation root.
854
    GenericInstantiationRequired,
855
    /// Internal error.
856
    Internal,
857
    /// A generic application supplied the wrong number of arguments.
858
    GenericArgumentCount(CountMismatch),
859
    /// A data specialization targeted a non-data generic declaration.
860
    GenericDataExpected,
861
    /// A data specialization argument still contains a rigid parameter.
862
    GenericConcreteArgumentsRequired,
863
    /// A declaration exceeds the generic parameter limit.
864
    GenericParameterLimit,
865
    /// A package exceeds the explicit generic root limit.
866
    GenericRootLimit,
867
    /// A package exceeds the canonical specialization limit.
868
    GenericSpecializationLimit,
869
}
870
871
/// Diagnostics returned by the analyzer.
872
export record Diagnostics {
873
    errors: *mut [Error],
874
}
875
876
/// Call context.
877
union CallCtx {
878
    /// Normal function call.
879
    Normal,
880
    /// Fallible function call, ie. `try f()`.
881
    Try,
882
}
883
884
/// Result of resolving a record literal's type name.
885
record ResolvedRecordLitType {
886
    /// The record nominal type to use for field checking.
887
    recordType: *NominalType,
888
    /// The result type of the literal (record type or union type for variants).
889
    resultType: Type,
890
}
891
892
/// Result of checking for a `super` path prefix.
893
record SuperAccessResult {
894
    scope: *mut Scope,
895
    child: *ast::Node,
896
}
897
898
/// Node-specific resolver metadata.
899
export union NodeExtra {
900
    /// No extra data for this node.
901
    None,
902
    /// Resolved field index for record literal fields.
903
    RecordField { index: u32 },
904
    /// Slice range metadata for subscript expressions with ranges.
905
    SliceRange(SliceRangeInfo),
906
    /// Cached union variant metadata for patterns/constructors.
907
    UnionVariant { ordinal: u32, tag: u32 },
908
    /// Match prong metadata.
909
    MatchProng { catchAll: bool },
910
    /// Match expression metadata.
911
    Match { isConst: bool },
912
    /// For-loop iteration metadata.
913
    ForLoop(ForLoopInfo),
914
    /// Trait method call metadata.
915
    TraitMethodCall {
916
        /// Trait definition.
917
        traitInfo: *TraitType,
918
        /// Method index in the v-table.
919
        methodIndex: u32,
920
    },
921
    /// Static method call through a bounded generic parameter.
922
    GenericBoundMethodCall {
923
        param: *GenericParamType,
924
        traitInfo: *TraitType,
925
        methodIndex: u32,
926
        /// Whether the receiver is the first explicit call argument.
927
        explicitReceiver: bool,
928
    },
929
    /// Standalone method call metadata.
930
    MethodCall { method: *MethodEntry },
931
    /// Slice `.append(val, allocator)` method call.
932
    SliceAppend { elemType: *Type },
933
    /// Slice `.delete(index)` method call.
934
    SliceDelete { elemType: *Type },
935
    /// Concrete specialization selected by an explicit generic function value.
936
    GenericFnCall(*GenericFnSpecialization),
937
    /// Symbolic generic call resolved under the caller's specialization.
938
    GenericFnDependency(*GenericFnDependency),
939
}
940
941
/// Combined resolver metadata for a single AST node.
942
export record NodeData {
943
    /// Resolved type for this node.
944
    ty: Type,
945
    /// Coercion plan applied to this node.
946
    coercion: Coercion,
947
    /// Symbol associated with this node.
948
    sym: ?*mut Symbol,
949
    /// Constant value for literal nodes.
950
    constValue: ?ConstValue,
951
    /// Lexical scope owned by this node.
952
    scope: ?*mut Scope,
953
    /// Node-specific extra data.
954
    extra: NodeExtra,
955
}
956
957
/// Table storing all resolver metadata indexed by node ID.
958
record NodeDataTable {
959
    entries: *mut [NodeData],
960
}
961
962
/// Lexical scope.
963
export record Scope {
964
    /// Owning AST node, or `nil` for the root scope.
965
    owner: ?*ast::Node,
966
    /// Parent/enclosing scope.
967
    parent: ?*mut Scope,
968
    /// Module ID if this is a module scope.
969
    moduleId: ?u16,
970
    /// Symbols introduced inside the scope, allocated from the arena.
971
    symbols: *mut [*mut Symbol],
972
    /// Number of live symbols.
973
    symbolsLen: u32,
974
}
975
976
/// An object used by the enter and exit functions for module scopes.
977
record ModuleScope {
978
    /// Module root node.
979
    root: *ast::Node,
980
    /// Module entry in graph.
981
    entry: *module::ModuleEntry,
982
    /// The newly entered scope.
983
    newScope: *mut Scope,
984
    /// The previous scope.
985
    prevScope: *mut Scope,
986
    /// The previous module.
987
    prevMod: u16,
988
}
989
990
/// Loop context for tracking control flow within loops.
991
record LoopCtx {
992
    /// Whether a reachable break was encountered in this loop.
993
    /// This is used to determine whether a loop diverges.
994
    hasBreak: bool,
995
}
996
997
/// Configuration for semantic analysis.
998
export record Config {
999
    /// Whether we're building in test mode.
1000
    buildTest: bool,
1001
}
1002
1003
/// How pattern bindings are created during match.
1004
export union MatchBy {
1005
    /// Match by value.
1006
    Value,
1007
    /// Match by immutable reference.
1008
    Ref,
1009
    /// Match by mutable reference.
1010
    MutRef,
1011
}
1012
1013
/// State of a match statement being resolved.
1014
// TODO: This is only used because of the maximum function param limitation.
1015
record MatchState {
1016
    /// Is the match catch-all?
1017
    catchAll: bool,
1018
    /// Is the match constant?
1019
    isConst: bool
1020
}
1021
1022
/// Result of unwrapping a type for pattern matching.
1023
export record MatchSubject {
1024
    /// The effective type to match against.
1025
    effectiveTy: Type,
1026
    /// How bindings should be created.
1027
    by: MatchBy,
1028
}
1029
1030
/// Unwrap a pointer type for pattern matching.
1031
export fn unwrapMatchSubject(ty: Type) -> MatchSubject {
1032
    if let case Type::Pointer(pointer) = ty {
1033
        let by = MatchBy::MutRef if pointer.mutable else MatchBy::Ref;
1034
        return MatchSubject { effectiveTy: *pointer.target, by };
1035
    }
1036
    return MatchSubject { effectiveTy: ty, by: MatchBy::Value };
1037
}
1038
1039
/// Global resolver state.
1040
export record Resolver {
1041
    /// Current scope.
1042
    scope: *mut Scope,
1043
    /// Package scope containing package roots and top-level symbols.
1044
    pkgScope: *mut Scope,
1045
    /// Stack of loop contexts for nested loops.
1046
    loopStack: [LoopCtx; MAX_LOOP_DEPTH],
1047
    /// Current loop depth, indexes into loop stack.
1048
    loopDepth: u32,
1049
    /// Signature of the function currently being analyzed.
1050
    currentFn: ?*FnType,
1051
    /// Rigid `Self` type while resolving a trait signature.
1052
    currentTraitSelf: ?*GenericParamType,
1053
    /// Current module being analyzed.
1054
    currentMod: u16,
1055
    /// Nesting depth of unsafe modules and function bodies.
1056
    unsafeDepth: u32,
1057
    /// Whether this compilation contains explicitly linear declarations.
1058
    linearEnabled: bool,
1059
    /// Configuration for semantic analysis.
1060
    config: Config,
1061
    /// Unified arena for symbols, scopes, and nominal type.
1062
    arena: alloc::Arena,
1063
    /// Combined semantic metadata table indexed by node ID.
1064
    nodeData: NodeDataTable,
1065
    /// Linked list of interned types.
1066
    types: ?*TypeNode,
1067
    /// Diagnostics recorded so far.
1068
    errors: *mut [Error],
1069
    /// Module graph for the current package.
1070
    moduleGraph: *module::ModuleGraph,
1071
    /// Cache of module scopes indexed by module ID.
1072
    moduleScopes: [?*mut Scope; module::MAX_MODULES],
1073
    /// Trait instance registry.
1074
    instances: [InstanceEntry; MAX_INSTANCES],
1075
    /// Number of registered instances.
1076
    instancesLen: u32,
1077
    /// Standalone method registry.
1078
    methods: [MethodEntry; MAX_METHODS],
1079
    /// Number of registered standalone methods.
1080
    methodsLen: u32,
1081
    /// Sparse metadata for generic declarations.
1082
    genericTemplates: ?*mut GenericTemplateNode,
1083
    /// Canonical generic function specializations.
1084
    genericFnSpecializations: ?*mut GenericFnSpecializationNode,
1085
    /// Symbolic and deferred generic call edges.
1086
    genericFnDependencies: ?*GenericFnDependency,
1087
    /// Concrete resolutions of symbolic generic call edges.
1088
    genericFnDependencyResolutions: ?*GenericFnDependencyResolution,
1089
    /// Package-wide canonical generic data specializations.
1090
    genericDataSpecializations: ?*GenericDataSpecializationNode,
1091
    /// Number of explicit generic roots requested by the package.
1092
    genericRoots: u32,
1093
    /// Number of canonical data and function specializations.
1094
    genericSpecializationCount: u32,
1095
}
1096
1097
/// Internal error sentinel thrown when analysis cannot proceed.
1098
export union ResolveError {
1099
    Failure,
1100
}
1101
1102
/// Node in the type interning linked list.
1103
record TypeNode {
1104
    ty: Type,
1105
    next: ?*TypeNode,
1106
}
1107
1108
/// Allocate and intern a type in the arena, returning a pointer for deduplication.
1109
export fn allocType(self: *mut Resolver, ty: Type) -> *Type {
1110
    // Search existing types for a match.
1111
    let mut cursor = self.types;
1112
    while let node = cursor {
1113
        if node.ty == ty {
1114
            return &node.ty;
1115
        }
1116
        set cursor = node.next;
1117
    }
1118
    // Allocate a new type node from the arena.
1119
    let node = try! alloc::alloc(
1120
        &mut self.arena, @sizeOf(TypeNode), @alignOf(TypeNode)
1121
    ) as *mut TypeNode;
1122
1123
    set *node = TypeNode { ty, next: self.types };
1124
    set self.types = node;
1125
1126
    return &node.ty;
1127
}
1128
1129
/// Return whether a type contains a rigid generic parameter.
1130
export fn containsGenericParameter(ty: Type) -> bool {
1131
    match ty {
1132
        case Type::Pointer(pointer) =>
1133
            return containsGenericParameter(*pointer.target),
1134
        case Type::Slice(slice) =>
1135
            return containsGenericParameter(*slice.item),
1136
        case Type::Parameter(_), Type::ConstParameter(_),
1137
             Type::GenericConstExpr { .. } => return true,
1138
        case Type::Array(array) => return containsGenericParameter(*array.item),
1139
        case Type::GenericArray { .. } => return true,
1140
        case Type::Optional(inner) => return containsGenericParameter(*inner),
1141
        // Symbolic anonymous records require materialization even when their
1142
        // own fields happen not to mention a rigid parameter.
1143
        case Type::GenericRecord(_) => return true,
1144
        case Type::GenericDataApply(_) => return true,
1145
        case Type::Fn(info) => {
1146
            for param in info.paramTypes {
1147
                if containsGenericParameter(*param) {
1148
                    return true;
1149
                }
1150
            }
1151
            if containsGenericParameter(*info.returnType) {
1152
                return true;
1153
            }
1154
            for thrown in info.throwList {
1155
                if containsGenericParameter(*thrown) {
1156
                    return true;
1157
                }
1158
            }
1159
            return false;
1160
        }
1161
        case Type::Range { start, end } => {
1162
            if let ty = start {
1163
                if containsGenericParameter(*ty) {
1164
                    return true;
1165
                }
1166
            }
1167
            if let ty = end {
1168
                if containsGenericParameter(*ty) {
1169
                    return true;
1170
                }
1171
            }
1172
            return false;
1173
        }
1174
        else => return false,
1175
    }
1176
}
1177
1178
/// Return whether a by-value type reaches an in-progress nominal placeholder.
1179
fn hasUnresolvedNominalLayout(ty: Type) -> bool {
1180
    match ty {
1181
        case Type::Pointer(_), Type::Slice(_) => return false,
1182
        case Type::Array(array) => return hasUnresolvedNominalLayout(*array.item),
1183
        case Type::Optional(inner) => return hasUnresolvedNominalLayout(*inner),
1184
        case Type::Nominal(info) => {
1185
            if let case NominalType::Placeholder(_) = *info {
1186
                return true;
1187
            }
1188
            return false;
1189
        }
1190
        case Type::GenericRecord(rec) => {
1191
            for field in rec.fields {
1192
                if hasUnresolvedNominalLayout(field.fieldType) {
1193
                    return true;
1194
                }
1195
            }
1196
            return false;
1197
        }
1198
        else => return false,
1199
    }
1200
}
1201
1202
/// Materialize concrete generic data applications within a type while
1203
/// preserving rigid parameters and constant-dependent constructors.
1204
fn materializeConcreteGenericData(
1205
    self: *mut Resolver,
1206
    ty: Type,
1207
    site: *ast::Node,
1208
) -> Type throws (ResolveError) {
1209
    match ty {
1210
        case Type::Pointer(pointer) => {
1211
            let inner = try materializeConcreteGenericData(self, *pointer.target, site);
1212
            return Type::Pointer(PointerType {
1213
                class: pointer.class,
1214
                target: allocType(self, inner),
1215
                mutable: pointer.mutable,
1216
            });
1217
        }
1218
        case Type::Slice(slice) => {
1219
            let inner = try materializeConcreteGenericData(self, *slice.item, site);
1220
            return Type::Slice(SliceType {
1221
                class: slice.class,
1222
                item: allocType(self, inner),
1223
                mutable: slice.mutable,
1224
            });
1225
        }
1226
        case Type::Array(array) => {
1227
            let item = try materializeConcreteGenericData(self, *array.item, site);
1228
            return Type::Array(ArrayType {
1229
                item: allocType(self, item),
1230
                length: array.length,
1231
            });
1232
        }
1233
        case Type::GenericArray { item, length } => {
1234
            let inner = try materializeConcreteGenericData(self, *item, site);
1235
            return Type::GenericArray { item: allocType(self, inner), length };
1236
        }
1237
        case Type::Optional(inner) => {
1238
            let value = try materializeConcreteGenericData(self, *inner, site);
1239
            return Type::Optional(allocType(self, value));
1240
        }
1241
        case Type::GenericDataApply(app) => {
1242
            let a = alloc::arenaAllocator(&mut self.arena);
1243
            let mut args: *mut [*Type] = &mut [];
1244
            let mut concrete = true;
1245
            for arg in app.args {
1246
                let value = try materializeConcreteGenericData(self, *arg, site);
1247
                set concrete = concrete and not containsGenericParameter(value);
1248
                args.append(allocType(self, value), a);
1249
            }
1250
            if concrete {
1251
                let nominal = try specializeGenericData(
1252
                    self, app.site, app.template, &args[..], false
1253
                );
1254
                return Type::Nominal(nominal);
1255
            }
1256
            let application = try! alloc::alloc(
1257
                &mut self.arena,
1258
                @sizeOf(GenericDataApplyType),
1259
                @alignOf(GenericDataApplyType),
1260
            ) as *mut GenericDataApplyType;
1261
            set *application = GenericDataApplyType {
1262
                template: app.template,
1263
                args: &args[..],
1264
                site: app.site,
1265
            };
1266
            return Type::GenericDataApply(application);
1267
        }
1268
        case Type::Fn(info) => {
1269
            let a = alloc::arenaAllocator(&mut self.arena);
1270
            let mut params: *mut [*Type] = &mut [];
1271
            let mut throwTypes: *mut [*Type] = &mut [];
1272
            for param in info.paramTypes {
1273
                let value = try materializeConcreteGenericData(self, *param, site);
1274
                params.append(allocType(self, value), a);
1275
            }
1276
            for thrown in info.throwList {
1277
                let value = try materializeConcreteGenericData(self, *thrown, site);
1278
                throwTypes.append(allocType(self, value), a);
1279
            }
1280
            let result = try materializeConcreteGenericData(
1281
                self, *info.returnType, site
1282
            );
1283
            return Type::Fn(allocFnType(self, FnType {
1284
                paramTypes: &params[..],
1285
                returnType: allocType(self, result),
1286
                throwList: &throwTypes[..],
1287
                isUnsafe: info.isUnsafe,
1288
                localCount: info.localCount,
1289
            }));
1290
        }
1291
        case Type::GenericRecord(rec) => {
1292
            let a = alloc::arenaAllocator(&mut self.arena);
1293
            let mut fields: *mut [RecordField] = &mut [];
1294
            let mut symbolic = false;
1295
            for field in rec.fields {
1296
                let fieldType = try materializeConcreteGenericData(
1297
                    self, field.fieldType, site
1298
                );
1299
                set symbolic = symbolic or containsGenericParameter(fieldType);
1300
                fields.append(RecordField {
1301
                    name: field.name,
1302
                    fieldType,
1303
                    offset: field.offset,
1304
                }, a);
1305
            }
1306
            let updatedRec = try! alloc::alloc(
1307
                &mut self.arena,
1308
                @sizeOf(GenericRecordType),
1309
                @alignOf(GenericRecordType),
1310
            ) as *mut GenericRecordType;
1311
            set *updatedRec = GenericRecordType {
1312
                fields: &fields[..],
1313
                labeled: rec.labeled,
1314
            };
1315
            let updated = Type::GenericRecord(updatedRec);
1316
            if symbolic {
1317
                return updated;
1318
            }
1319
            let empty = Substitution { params: &[], args: &[] };
1320
            return try substituteType(self, updated, &empty, site);
1321
        }
1322
        else => return ty,
1323
    }
1324
}
1325
1326
/// Look up the concrete replacement for a rigid parameter.
1327
export fn substitutionArg(sub: *Substitution, param: *GenericParamType) -> Type {
1328
    assert sub.params.len == sub.args.len, "substitution length mismatch";
1329
    for candidate, i in sub.params {
1330
        if candidate == param {
1331
            return *sub.args[i];
1332
        }
1333
    }
1334
    if param.constType <> nil {
1335
        return Type::ConstParameter(param);
1336
    }
1337
    return Type::Parameter(param);
1338
}
1339
1340
/// Recursively replace rigid parameters in a resolved type.
1341
export fn substituteType(
1342
    self: *mut Resolver,
1343
    ty: Type,
1344
    sub: *Substitution,
1345
    site: *ast::Node,
1346
) -> Type throws (ResolveError) {
1347
    if not containsGenericParameter(ty) {
1348
        return ty;
1349
    }
1350
    match ty {
1351
        case Type::Parameter(param) => return substitutionArg(sub, param),
1352
        case Type::ConstParameter(param) => return substitutionArg(sub, param),
1353
        case Type::GenericConstExpr { type, expr } => {
1354
            let value = constValueWithSubstitution(self, expr, sub)
1355
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
1356
            let case ConstValue::Int(int) = value
1357
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
1358
            if not validateConstIntRange(value, *type) {
1359
                throw emitError(self, expr, ErrorKind::NumericLiteralOverflow);
1360
            }
1361
            let case ConstValue::Int(canonical) = castConstInt(int, *type)
1362
                else throw emitError(self, expr, ErrorKind::Internal);
1363
            return Type::ConstArgument { type, value: canonical };
1364
        }
1365
        case Type::Pointer(pointer) => {
1366
            let inner = try substituteType(self, *pointer.target, sub, site);
1367
            return Type::Pointer(PointerType {
1368
                class: pointer.class,
1369
                target: allocType(self, inner),
1370
                mutable: pointer.mutable,
1371
            });
1372
        }
1373
        case Type::Slice(slice) => {
1374
            let inner = try substituteType(self, *slice.item, sub, site);
1375
            return Type::Slice(SliceType {
1376
                class: slice.class,
1377
                item: allocType(self, inner),
1378
                mutable: slice.mutable,
1379
            });
1380
        }
1381
        case Type::Array(array) => {
1382
            let item = try substituteType(self, *array.item, sub, site);
1383
            return Type::Array(ArrayType {
1384
                item: allocType(self, item),
1385
                length: array.length,
1386
            });
1387
        }
1388
        case Type::GenericArray { item, length } => {
1389
            let concreteItem = try substituteType(self, *item, sub, site);
1390
            let value = constValueWithSubstitution(self, length, sub)
1391
                else throw emitError(self, length, ErrorKind::ConstExprRequired);
1392
            if not validateConstIntRange(value, Type::U32) {
1393
                throw emitError(self, length, ErrorKind::NumericLiteralOverflow);
1394
            }
1395
            let case ConstValue::Int(int) = value
1396
                else throw emitError(self, length, ErrorKind::ConstExprRequired);
1397
            return Type::Array(ArrayType {
1398
                item: allocType(self, concreteItem),
1399
                length: int.magnitude as u32,
1400
            });
1401
        }
1402
        case Type::Optional(inner) => {
1403
            let value = try substituteType(self, *inner, sub, site);
1404
            return Type::Optional(allocType(self, value));
1405
        }
1406
        case Type::GenericDataApply(app) => {
1407
            let a = alloc::arenaAllocator(&mut self.arena);
1408
            let mut args: *mut [*Type] = &mut [];
1409
            let mut symbolic = false;
1410
            for arg in app.args {
1411
                let replacement = try substituteType(self, *arg, sub, site);
1412
                set symbolic = symbolic or containsGenericParameter(replacement);
1413
                args.append(allocType(self, replacement), a);
1414
            }
1415
            if symbolic {
1416
                let application = try! alloc::alloc(
1417
                    &mut self.arena,
1418
                    @sizeOf(GenericDataApplyType),
1419
                    @alignOf(GenericDataApplyType),
1420
                ) as *mut GenericDataApplyType;
1421
                set *application = GenericDataApplyType {
1422
                    template: app.template,
1423
                    args: &args[..],
1424
                    site: app.site,
1425
                };
1426
                return Type::GenericDataApply(application);
1427
            }
1428
            let nominal = try specializeGenericData(
1429
                self, app.site, app.template, &args[..], false
1430
            );
1431
            return Type::Nominal(nominal);
1432
        }
1433
        case Type::GenericRecord(rec) => {
1434
            let a = alloc::arenaAllocator(&mut self.arena);
1435
            let mut fields: *mut [RecordField] = &mut [];
1436
            let mut offset: u32 = 0;
1437
            let mut alignment: u32 = 1;
1438
            for field in rec.fields {
1439
                let fieldType = try substituteType(self, field.fieldType, sub, site);
1440
                if hasUnresolvedNominalLayout(fieldType) {
1441
                    throw emitError(self, site, ErrorKind::GenericRecursiveLayout);
1442
                }
1443
                try ensureStorableType(self, site, fieldType);
1444
                try ensureTypeResolved(self, fieldType, site);
1445
                let fieldLayout = getTypeLayout(fieldType);
1446
                set offset = mem::alignUp(offset, fieldLayout.alignment);
1447
                fields.append(RecordField {
1448
                    name: field.name,
1449
                    fieldType,
1450
                    offset: offset as i32,
1451
                }, a);
1452
                set offset += fieldLayout.size;
1453
                set alignment = max(alignment, fieldLayout.alignment);
1454
            }
1455
            let layout = Layout {
1456
                size: mem::alignUp(offset, alignment),
1457
                alignment,
1458
            };
1459
            return Type::Nominal(allocNominalType(self, NominalType::Record(RecordType {
1460
                fields: &fields[..],
1461
                labeled: rec.labeled,
1462
                layout,
1463
                declaredLinear: false,
1464
            })));
1465
        }
1466
        case Type::Fn(info) => {
1467
            let a = alloc::arenaAllocator(&mut self.arena);
1468
            let mut params: *mut [*Type] = &mut [];
1469
            let mut throwTypes: *mut [*Type] = &mut [];
1470
            for param in info.paramTypes {
1471
                let concrete = try substituteType(self, *param, sub, site);
1472
                params.append(allocType(self, concrete), a);
1473
            }
1474
            for thrown in info.throwList {
1475
                let concrete = try substituteType(self, *thrown, sub, site);
1476
                throwTypes.append(allocType(self, concrete), a);
1477
            }
1478
            let result = try substituteType(self, *info.returnType, sub, site);
1479
            return Type::Fn(allocFnType(self, FnType {
1480
                paramTypes: &params[..],
1481
                returnType: allocType(self, result),
1482
                throwList: &throwTypes[..],
1483
                isUnsafe: info.isUnsafe,
1484
                localCount: info.localCount,
1485
            }));
1486
        }
1487
        case Type::Range { start, end } => {
1488
            let mut newStart: ?*Type = nil;
1489
            let mut newEnd: ?*Type = nil;
1490
            if let value = start {
1491
                let concrete = try substituteType(self, *value, sub, site);
1492
                set newStart = allocType(self, concrete);
1493
            }
1494
            if let value = end {
1495
                let concrete = try substituteType(self, *value, sub, site);
1496
                set newEnd = allocType(self, concrete);
1497
            }
1498
            return Type::Range { start: newStart, end: newEnd };
1499
        }
1500
        else => return ty,
1501
    }
1502
}
1503
1504
/// Allocate a nominal type descriptor and return a pointer to it.
1505
fn allocNominalType(self: *mut Resolver, info: NominalType) -> *mut NominalType {
1506
    // Nb. We don't attempt to de-duplicate nominal type entries,
1507
    // since they don't carry node information and we create
1508
    // placeholder entries when binding symbols.
1509
    let entry = try! alloc::alloc(
1510
        &mut self.arena, @sizeOf(NominalType), @alignOf(NominalType)
1511
    ) as *mut NominalType;
1512
1513
    set *entry = info;
1514
1515
    return entry;
1516
}
1517
1518
/// Allocate a function type descriptor and return a pointer to it.
1519
fn allocFnType(self: *mut Resolver, info: FnType) -> *FnType {
1520
    let entry = try! alloc::alloc(
1521
        &mut self.arena, @sizeOf(FnType), @alignOf(FnType)
1522
    ) as *mut FnType;
1523
1524
    set *entry = info;
1525
1526
    return entry;
1527
}
1528
1529
/// Returns an error, if any, associated with the given node.
1530
fn errorForNode(self: *Resolver, node: *ast::Node) -> ?*Error {
1531
    for i in 0..self.errors.len {
1532
        let err = &self.errors[i];
1533
        if err.node == node {
1534
            return err;
1535
        }
1536
    }
1537
    return nil;
1538
}
1539
1540
/// Storage buffers used by the analyzer.
1541
export record ResolverStorage {
1542
    /// Unified arena for symbols, scopes, and nominal type.
1543
    arena: alloc::Arena,
1544
    /// Node semantic metadata indexed by node ID.
1545
    nodeData: *mut [NodeData],
1546
    /// Package scope.
1547
    pkgScope: *mut Scope,
1548
    /// Error storage.
1549
    errors: *mut [Error],
1550
}
1551
1552
/// Input for resolving a single package.
1553
export record Pkg {
1554
    /// Root module entry.
1555
    rootEntry: *module::ModuleEntry,
1556
    /// Root AST node.
1557
    rootAst: *ast::Node,
1558
}
1559
1560
/// Construct a resolver with module context and backing storage.
1561
export fn resolver(
1562
    storage: ResolverStorage,
1563
    config: Config
1564
) -> Resolver {
1565
    let mut arena = storage.arena;
1566
    let symbols = try! alloc::allocSlice(
1567
        &mut arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), MAX_MODULE_SYMBOLS
1568
    ) as *mut [*mut Symbol];
1569
1570
    // Initialize the root scope.
1571
    // TODO: Set this up when declaring `PKG_SCOPE`, not here.
1572
    set *storage.pkgScope = Scope {
1573
        owner: nil,
1574
        parent: nil,
1575
        moduleId: nil,
1576
        symbols,
1577
        symbolsLen: 0,
1578
    };
1579
1580
    // Clear all node semantic metadata to sentinel values.
1581
    // TODO: Use array repeat literal?
1582
    for i in 0..storage.nodeData.len {
1583
        set storage.nodeData[i] = NodeData {
1584
            ty: Type::Unknown,
1585
            coercion: Coercion::Identity,
1586
            sym: nil,
1587
            constValue: nil,
1588
            scope: nil,
1589
            extra: NodeExtra::None,
1590
        };
1591
    }
1592
1593
    let mut moduleScopes: [?*mut Scope; module::MAX_MODULES] = undefined;
1594
    // TODO: Simplify.
1595
    for i in 0..moduleScopes.len {
1596
        set moduleScopes[i] = nil;
1597
    }
1598
    return Resolver {
1599
        scope: storage.pkgScope,
1600
        pkgScope: storage.pkgScope,
1601
        loopStack: undefined,
1602
        loopDepth: 0,
1603
        currentFn: nil,
1604
        currentTraitSelf: nil,
1605
        currentMod: 0,
1606
        unsafeDepth: 0,
1607
        linearEnabled: false,
1608
        config,
1609
        arena,
1610
        nodeData: NodeDataTable { entries: storage.nodeData },
1611
        types: nil,
1612
        errors: @sliceOf(storage.errors.ptr, 0, storage.errors.len),
1613
        // TODO: Shouldn't be undefined.
1614
        moduleGraph: undefined,
1615
        moduleScopes,
1616
        instances: undefined,
1617
        instancesLen: 0,
1618
        methods: undefined,
1619
        methodsLen: 0,
1620
        genericTemplates: nil,
1621
        genericFnSpecializations: nil,
1622
        genericFnDependencies: nil,
1623
        genericFnDependencyResolutions: nil,
1624
        genericDataSpecializations: nil,
1625
        genericRoots: 0,
1626
        genericSpecializationCount: 0,
1627
    };
1628
}
1629
1630
/// Return `true` if there are no errors in the diagnostics.
1631
export fn success(diag: *Diagnostics) -> bool {
1632
    return diag.errors.len == 0;
1633
}
1634
1635
/// Retrieve an error diagnostic by index, if present.
1636
export fn errorAt(errs: *[Error], index: u32) -> ?*Error {
1637
    if index >= errs.len {
1638
        return nil;
1639
    }
1640
    return &errs[index];
1641
}
1642
1643
/// Record an error diagnostic and return an error sentinel suitable for throwing.
1644
fn emitError(self: *mut Resolver, node: ?*ast::Node, kind: ErrorKind) -> ResolveError {
1645
    // If our error list is full, just return an error without recording it.
1646
    if self.errors.len >= self.errors.cap {
1647
        return ResolveError::Failure;
1648
    }
1649
    // Don't record more than one error per node.
1650
    if let n = node; errorForNode(self, n) <> nil {
1651
        return ResolveError::Failure;
1652
    }
1653
    let idx = self.errors.len;
1654
    set self.errors = @sliceOf(self.errors.ptr, idx + 1, self.errors.cap);
1655
    set self.errors[idx] = Error { kind, node, moduleId: self.currentMod };
1656
1657
    return ResolveError::Failure;
1658
}
1659
1660
/// Like [`emitError`], but for type mismatches specifically.
1661
fn emitTypeMismatch(self: *mut Resolver, node: ?*ast::Node, mismatch: TypeMismatch) -> ResolveError {
1662
    return emitError(self, node, ErrorKind::TypeMismatch(mismatch));
1663
}
1664
1665
/// Allocate a scope object with the given symbol capacity.
1666
fn allocScope(self: *mut Resolver, owner: *ast::Node, capacity: u32) -> *mut Scope {
1667
    // Check for an existing scope for this node, and don't allocate a new
1668
    // one in that case.
1669
    if let scope = scopeFor(self, owner) {
1670
        return scope;
1671
    }
1672
    assert owner.id < self.nodeData.entries.len, "allocScope: node ID out of bounds";
1673
    let p = try! alloc::alloc(&mut self.arena, @sizeOf(Scope), @alignOf(Scope));
1674
    let entry = p as *mut Scope;
1675
1676
    // Allocate symbols from the arena.
1677
    let symbols = try! alloc::allocSlice(
1678
        &mut self.arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), capacity
1679
    ) as *mut [*mut Symbol];
1680
1681
    set *entry = Scope { owner, parent: nil, moduleId: nil, symbols, symbolsLen: 0 };
1682
    set self.nodeData.entries[owner.id].scope = entry;
1683
1684
    return entry;
1685
}
1686
1687
/// Enter a new local scope that is the child of the current scope.
1688
/// This creates a parent/child relationship that means that lookups in the
1689
/// child scope can recurse upwards.
1690
export fn enterScope(self: *mut Resolver, owner: *ast::Node) -> *Scope {
1691
    let scope = allocScope(self, owner, MAX_LOCAL_SYMBOLS);
1692
    set scope.parent = self.scope;
1693
    set self.scope = scope;
1694
    return scope;
1695
}
1696
1697
/// Enter a module scope. Returns an object that can be used to exit the scope.
1698
export fn enterModuleScope(self: *mut Resolver, owner: *ast::Node, module: *module::ModuleEntry) -> ModuleScope {
1699
    let prevScope = self.scope;
1700
    let prevMod = self.currentMod;
1701
    let scope = allocScope(self, owner, MAX_MODULE_SYMBOLS);
1702
1703
    set self.scope = scope;
1704
    set self.scope.moduleId = module.id;
1705
    set self.currentMod = module.id;
1706
    // TODO: Allow any unsigned integer to index an array.
1707
    set self.moduleScopes[module.id as u32] = scope;
1708
1709
    return ModuleScope { root: owner, entry: module, newScope: scope, prevScope, prevMod };
1710
}
1711
1712
/// Enter a sub-module. Changes the current scope into that of the sub-module.
1713
fn enterSubModule(self: *mut Resolver, name: *[u8], node: *ast::Node) -> ModuleScope throws (ResolveError) {
1714
    let modEntry = module::findChild(self.moduleGraph, name, self.currentMod)
1715
        else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
1716
    let modRoot = modEntry.ast
1717
        else panic "enterSubModule: analyzing module that wasn't parsed";
1718
1719
    return enterModuleScope(self, modRoot, modEntry);
1720
}
1721
1722
/// Exit a module scope, given the object returned by `enterModuleScope`.
1723
export fn exitModuleScope(self: *mut Resolver, entry: ModuleScope) {
1724
    set self.scope = entry.prevScope;
1725
    set self.currentMod = entry.prevMod;
1726
}
1727
1728
/// Exit the most recent scope.
1729
export fn exitScope(self: *mut Resolver) {
1730
    let parent = self.scope.parent else {
1731
        // TODO: This should be a panic, but one of the tests hits this
1732
        // clause, which might be a bug in the generator.
1733
        return;
1734
    };
1735
    set self.scope = parent;
1736
}
1737
1738
/// Visit the body of a loop while tracking nesting depth.
1739
fn visitLoop(self: *mut Resolver, body: *ast::Node) -> Type
1740
    throws (ResolveError)
1741
{
1742
    assert self.loopDepth < MAX_LOOP_DEPTH, "visitLoop: loop nesting depth exceeded";
1743
    set self.loopStack[self.loopDepth] = LoopCtx { hasBreak: false };
1744
    set self.loopDepth += 1;
1745
1746
    let ty = try infer(self, body) catch {
1747
        assert self.loopDepth <> 0, "visitLoop: loop depth underflow";
1748
        set self.loopDepth -= 1;
1749
        throw ResolveError::Failure;
1750
    };
1751
    // Pop and check if break was encountered.
1752
    set self.loopDepth -= 1;
1753
1754
    if self.loopStack[self.loopDepth].hasBreak {
1755
        return Type::Void;
1756
    }
1757
    return Type::Never;
1758
}
1759
1760
/// Require that loop control statements appear inside a loop.
1761
fn ensureInsideLoop(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
1762
    if self.loopDepth == 0 {
1763
        throw emitError(self, node, ErrorKind::InvalidLoopControl);
1764
    }
1765
}
1766
1767
/// Bind a loop pattern to the provided type.
1768
fn bindForLoopPattern(self: *mut Resolver, pattern: *ast::Node, ty: Type, mutable: bool)
1769
    throws (ResolveError)
1770
{
1771
    match pattern.value {
1772
        case ast::NodeValue::Placeholder, ast::NodeValue::Ident(_) => {
1773
            let _ = try bindValueIdent(self, pattern, pattern, ty, mutable, 0, 0);
1774
        }
1775
        else => {
1776
            let actualTy = try checkAssignable(self, pattern, ty);
1777
            setNodeType(self, pattern, actualTy);
1778
        }
1779
    }
1780
}
1781
1782
/// Set the expected return type for a new function body.
1783
fn enterFn(self: *mut Resolver, node: *ast::Node, ty: *FnType) {
1784
    assert self.currentFn == nil, "enterFn: already in a function";
1785
    set self.currentFn = ty;
1786
    enterScope(self, node);
1787
}
1788
1789
/// Clear the expected return type when leaving a function body.
1790
fn exitFn(self: *mut Resolver) {
1791
    if self.currentFn == nil {
1792
        // TODO: This should be a panic, but one of the tests hits this
1793
        // clause, which might be a bug in the generator.
1794
        return;
1795
    }
1796
    set self.currentFn = nil;
1797
    exitScope(self);
1798
}
1799
1800
/// Extract the identifier text from a node.
1801
fn nodeName(self: *mut Resolver, node: *ast::Node) -> *[u8]
1802
    throws (ResolveError)
1803
{
1804
    let case ast::NodeValue::Ident(name) = node.value
1805
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
1806
    return name;
1807
}
1808
1809
/// Associate a resolved symbol with an AST node.
1810
fn setNodeSymbol(self: *mut Resolver, node: *ast::Node, symbol: *mut Symbol) {
1811
    if let existingSym = self.nodeData.entries[node.id].sym {
1812
        panic "setNodeSymbol: a symbol is already associated with this node";
1813
    }
1814
    set self.nodeData.entries[node.id].sym = symbol;
1815
}
1816
1817
/// Associate a resolved type with an AST node and return it.
1818
fn setNodeType(self: *mut Resolver, node: *ast::Node, ty: Type) -> Type {
1819
    if ty == Type::Unknown {
1820
        // In this case, we simply don't associate a type.
1821
        return ty;
1822
    }
1823
    set self.nodeData.entries[node.id].ty = ty;
1824
1825
    return ty;
1826
}
1827
1828
/// Unify the types of two branches for control flow. Returns `never` only if
1829
/// both branches diverge, otherwise returns `void`. If the else branch is
1830
/// absent, we assume it doesn't diverge.
1831
fn unifyBranches(left: Type, right: ?Type) -> Type {
1832
    if left == Type::Never {
1833
        if let ty = right; ty == Type::Never {
1834
            return Type::Never;
1835
        }
1836
    }
1837
    return Type::Void;
1838
}
1839
1840
/// Associate a coercion plan with an AST node.
1841
fn setNodeCoercion(self: *mut Resolver, node: *ast::Node, coercion: Coercion) -> Coercion {
1842
    if coercion == Coercion::Identity {
1843
        return coercion;
1844
    }
1845
    set self.nodeData.entries[node.id].coercion = coercion;
1846
1847
    return coercion;
1848
}
1849
1850
/// Associate a constant value with an AST node.
1851
fn setNodeConstValue(self: *mut Resolver, node: *ast::Node, value: ConstValue) {
1852
    set self.nodeData.entries[node.id].constValue = value;
1853
}
1854
1855
/// Associate a record field index with a record literal field node.
1856
fn setRecordFieldIndex(self: *mut Resolver, node: *ast::Node, index: u32) {
1857
    set self.nodeData.entries[node.id].extra = NodeExtra::RecordField { index };
1858
}
1859
1860
/// Associate slice range metadata with a subscript expression.
1861
fn setSliceRangeInfo(self: *mut Resolver, node: *ast::Node, info: SliceRangeInfo) {
1862
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceRange(info);
1863
}
1864
1865
/// Associate union variant metadata with a pattern or constructor node.
1866
fn setVariantInfo(self: *mut Resolver, node: *ast::Node, ordinal: u32, tag: u32) {
1867
    set self.nodeData.entries[node.id].extra = NodeExtra::UnionVariant { ordinal, tag };
1868
}
1869
1870
/// Associate trait method call metadata with a call node.
1871
fn setTraitMethodCall(self: *mut Resolver, node: *ast::Node, traitInfo: *TraitType, methodIndex: u32) {
1872
    set self.nodeData.entries[node.id].extra = NodeExtra::TraitMethodCall { traitInfo, methodIndex };
1873
}
1874
1875
/// Associate static generic-bound dispatch metadata with a call node.
1876
fn setGenericBoundMethodCall(
1877
    self: *mut Resolver,
1878
    node: *ast::Node,
1879
    param: *GenericParamType,
1880
    traitInfo: *TraitType,
1881
    methodIndex: u32,
1882
    explicitReceiver: bool,
1883
) {
1884
    set self.nodeData.entries[node.id].extra = NodeExtra::GenericBoundMethodCall {
1885
        param, traitInfo, methodIndex, explicitReceiver,
1886
    };
1887
}
1888
1889
/// Associate for-loop metadata with a for-loop node.
1890
fn setForLoopInfo(self: *mut Resolver, node: *ast::Node, info: ForLoopInfo) {
1891
    set self.nodeData.entries[node.id].extra = NodeExtra::ForLoop(info);
1892
}
1893
1894
/// Retrieve the constant value associated with a node, if any.
1895
export fn constValueEntry(self: *Resolver, node: *ast::Node) -> ?ConstValue {
1896
    return self.nodeData.entries[node.id].constValue;
1897
}
1898
1899
/// Get the resolved record field index for a record literal field node.
1900
export fn recordFieldIndexFor(self: *Resolver, node: *ast::Node) -> ?u32 {
1901
    if let case NodeExtra::RecordField { index } = self.nodeData.entries[node.id].extra {
1902
        return index;
1903
    }
1904
    return nil;
1905
}
1906
1907
/// Get the slice range metadata for a subscript expression with a range index.
1908
export fn sliceRangeInfoFor(self: *Resolver, node: *ast::Node) -> ?SliceRangeInfo {
1909
    if let case NodeExtra::SliceRange(info) = self.nodeData.entries[node.id].extra {
1910
        return info;
1911
    }
1912
    return nil;
1913
}
1914
1915
/// Get the for-loop metadata for a for-loop node.
1916
export fn forLoopInfoFor(self: *Resolver, node: *ast::Node) -> ?ForLoopInfo {
1917
    if let case NodeExtra::ForLoop(info) = self.nodeData.entries[node.id].extra {
1918
        return info;
1919
    }
1920
    return nil;
1921
}
1922
1923
/// Associate match prong metadata with a match prong node.
1924
fn setProngCatchAll(self: *mut Resolver, node: *ast::Node, catchAll: bool) {
1925
    set self.nodeData.entries[node.id].extra = NodeExtra::MatchProng { catchAll };
1926
}
1927
1928
/// Check if a prong is catch-all.
1929
export fn isProngCatchAll(self: *Resolver, node: *ast::Node) -> bool {
1930
    if let case NodeExtra::MatchProng { catchAll } = self.nodeData.entries[node.id].extra {
1931
        return catchAll;
1932
    }
1933
    return false;
1934
}
1935
1936
/// Set match metadata.
1937
fn setMatchConst(self: *mut Resolver, node: *ast::Node, isConst: bool) {
1938
    set self.nodeData.entries[node.id].extra = NodeExtra::Match { isConst };
1939
}
1940
1941
/// Check if a match has all constant patterns.
1942
export fn isMatchConst(self: *Resolver, node: *ast::Node) -> bool {
1943
    if let case NodeExtra::Match { isConst } = self.nodeData.entries[node.id].extra {
1944
        return isConst;
1945
    }
1946
    return false;
1947
}
1948
1949
/// Get the resolver metadata for a node.
1950
export fn nodeData(self: *Resolver, node: *ast::Node) -> *NodeData {
1951
    return &self.nodeData.entries[node.id];
1952
}
1953
1954
/// Get the type for a node, or `nil` if unknown.
1955
export fn typeFor(self: *Resolver, node: *ast::Node) -> ?Type {
1956
    let ty = self.nodeData.entries[node.id].ty;
1957
    if ty == Type::Unknown {
1958
        return nil;
1959
    }
1960
    return ty;
1961
}
1962
1963
/// Get the scope associated with a node.
1964
export fn scopeFor(self: *Resolver, node: *ast::Node) -> ?*mut Scope {
1965
    return self.nodeData.entries[node.id].scope;
1966
}
1967
1968
/// Get the symbol bound to a node.
1969
export fn symbolFor(self: *Resolver, node: *ast::Node) -> ?*mut Symbol {
1970
    return self.nodeData.entries[node.id].sym;
1971
}
1972
1973
/// Get the coercion plan associated with a node, if any.
1974
export fn coercionFor(self: *Resolver, node: *ast::Node) -> ?Coercion {
1975
    let c = self.nodeData.entries[node.id].coercion;
1976
    if c == Coercion::Identity {
1977
        return nil;
1978
    }
1979
    return c;
1980
}
1981
1982
/// Get the module ID for a symbol by walking up its scope chain.
1983
export fn moduleIdForSymbol(self: *Resolver, sym: *Symbol) -> ?u16 {
1984
    // For module-level symbols, return the cached module ID.
1985
    if let id = sym.moduleId {
1986
        return id;
1987
    }
1988
    // For module symbols, return the module ID directly.
1989
    if let case SymbolData::Module { entry, .. } = sym.data {
1990
        return entry.id;
1991
    }
1992
    // If this node has its own scope (functions, types, etc.), walk up from there.
1993
    if let scope = self.nodeData.entries[sym.node.id].scope {
1994
        return findModuleForScope(scope);
1995
    }
1996
    return nil;
1997
}
1998
1999
/// Get the binding node for a variant pattern.
2000
/// Returns the argument node if this is a variant constructor with a non-placeholder binding.
2001
export fn variantPatternBinding(self: *Resolver, pattern: *ast::Node) -> ?*ast::Node {
2002
    let case ast::NodeValue::Call(call) = pattern.value
2003
        else return nil;
2004
    let sym = symbolFor(self, call.callee)
2005
        else return nil;
2006
    let case SymbolData::Variant { .. } = sym.data
2007
        else return nil;
2008
2009
    if call.args.len == 0 {
2010
        return nil;
2011
    }
2012
    let arg = call.args[0];
2013
2014
    if let case ast::NodeValue::Placeholder = arg.value {
2015
        return nil;
2016
    }
2017
    return arg;
2018
}
2019
2020
/// Allocate a new symbol, and return a reference to it.
2021
fn allocSymbol(self: *mut Resolver, data: SymbolData, name: *[u8], node: *ast::Node, attrs: u32) -> *mut Symbol {
2022
    let sym = try! alloc::alloc(&mut self.arena, @sizeOf(Symbol), @alignOf(Symbol)) as *mut Symbol;
2023
    set *sym = Symbol { name, data, attrs, node, moduleId: nil };
2024
2025
    return sym;
2026
}
2027
2028
/// Check that a type is boolean, otherwise throw an error.
2029
fn checkBoolean(self: *mut Resolver, node: *ast::Node) -> Type throws (ResolveError) {
2030
    return try checkEqual(self, node, Type::Bool);
2031
}
2032
2033
/// Check that a type is numeric, otherwise throw an error.
2034
fn checkNumeric(self: *mut Resolver, node: *ast::Node) -> Type throws (ResolveError) {
2035
    let ty = try infer(self, node);
2036
    if not isNumericType(ty) {
2037
        throw emitError(self, node, ErrorKind::ExpectedNumeric);
2038
    }
2039
    return ty;
2040
}
2041
2042
/// Check if a type is a numeric type.
2043
fn isNumericType(ty: Type) -> bool {
2044
    match ty {
2045
        case Type::U8, Type::U16, Type::U32, Type::U64,
2046
             Type::I8, Type::I16, Type::I32, Type::I64,
2047
             Type::Int => return true,
2048
        else => return false,
2049
    }
2050
}
2051
2052
/// Check if a type is an unsigned integer type.
2053
export fn isUnsignedIntegerType(ty: Type) -> bool {
2054
    match ty {
2055
        case Type::U8, Type::U16, Type::U32, Type::U64 => return true,
2056
        else => return false,
2057
    }
2058
}
2059
2060
/// Return the maximum of two u32 values.
2061
fn max(a: u32, b: u32) -> u32 {
2062
    if a > b {
2063
        return a;
2064
    }
2065
    return b;
2066
}
2067
2068
/// Get the layout of a type.
2069
export fn getTypeLayout(ty: Type) -> Layout {
2070
    match ty {
2071
        case Type::Pointer(_) => return Layout { size: PTR_SIZE, alignment: PTR_SIZE },
2072
        case Type::Slice(_), Type::TraitObject(_) =>
2073
            return Layout { size: PTR_SIZE * 2, alignment: PTR_SIZE },
2074
        case Type::Void, Type::Never => return Layout { size: 0, alignment: 0 },
2075
        case Type::Bool, Type::U8, Type::I8 => return Layout { size: 1, alignment: 1 },
2076
        case Type::U16, Type::I16 => return Layout { size: 2, alignment: 2 },
2077
        case Type::U32, Type::I32 => return Layout { size: 4, alignment: 4 },
2078
        case Type::Int => return Layout { size: 8, alignment: 8 },
2079
        case Type::U64, Type::I64 => return Layout { size: 8, alignment: 8 },
2080
        case Type::Fn(_) => return Layout { size: PTR_SIZE, alignment: PTR_SIZE },
2081
        case Type::Array(arr) => return getArrayLayout(arr),
2082
        case Type::Optional(inner) => return getOptionalLayout(*inner),
2083
        case Type::Nominal(info) => return getNominalLayout(*info),
2084
        else => {
2085
            panic "getTypeLayout: the given type cannot be layed out";
2086
        }
2087
    }
2088
}
2089
2090
/// Get the layout of a type or value.
2091
export fn getLayout(self: *Resolver, node: *ast::Node, ty: Type) -> Layout {
2092
    let mut layout = getTypeLayout(ty);
2093
    // Check for symbol-specific alignment override.
2094
    if let sym = symbolFor(self, node) {
2095
        if let case SymbolData::Value { alignment, .. } = sym.data {
2096
            if alignment > 0 {
2097
                set layout.alignment = alignment;
2098
            }
2099
        }
2100
    }
2101
    return layout;
2102
}
2103
2104
/// Get the layout of an array type.
2105
export fn getArrayLayout(arr: ArrayType) -> Layout {
2106
    let itemLayout = getTypeLayout(*arr.item);
2107
    return Layout {
2108
        size: itemLayout.size * arr.length,
2109
        alignment: itemLayout.alignment,
2110
    };
2111
}
2112
2113
/// Get the layout of an optional type.
2114
export fn getOptionalLayout(inner: Type) -> Layout {
2115
    // Nullable types use null pointer optimization -- no tag byte needed.
2116
    if isNullableType(inner) {
2117
        return getTypeLayout(inner);
2118
    }
2119
    let innerLayout = getTypeLayout(inner);
2120
    let tagSize: u32 = 1;
2121
    let valOffset = mem::alignUp(tagSize, innerLayout.alignment);
2122
    let alignment = max(innerLayout.alignment, 1);
2123
2124
    return Layout {
2125
        size: mem::alignUp(valOffset + innerLayout.size, alignment),
2126
        alignment,
2127
    };
2128
}
2129
2130
/// Get the payload offset within an optional aggregate.
2131
export fn getOptionalValOffset(inner: Type) -> u32 {
2132
    let innerLayout = getTypeLayout(inner);
2133
    return mem::alignUp(1, innerLayout.alignment);
2134
}
2135
2136
/// Check if a type is optional.
2137
export fn isOptionalType(ty: Type) -> bool {
2138
    match ty {
2139
        case Type::Optional(_) => return true,
2140
        else => return false,
2141
    }
2142
}
2143
2144
/// Check if a type uses null pointer optimization.
2145
/// This applies to optional pointers `?*T` and optional slices `?*[T]`,
2146
/// where `nil` is represented as a null data pointer with no tag byte.
2147
export fn isOptionalPointer(ty: Type) -> bool {
2148
    if let case Type::Optional(inner) = ty {
2149
        return isNullableType(*inner);
2150
    }
2151
    return false;
2152
}
2153
2154
/// Check if a type uses the optional aggregate representation.
2155
export fn isOptionalAggregate(ty: Type) -> bool {
2156
    if let case Type::Optional(inner) = ty {
2157
        return not isNullableType(*inner);
2158
    }
2159
    return false;
2160
}
2161
2162
/// Check if a type can use null to represent `nil`.
2163
/// Pointers and slices have a data pointer that is never null when valid.
2164
export fn isNullableType(ty: Type) -> bool {
2165
    match ty {
2166
        case Type::Pointer(_), Type::Slice(_) => return true,
2167
        else => return false,
2168
    }
2169
}
2170
2171
/// Get the layout of a nominal type.
2172
export fn getNominalLayout(info: NominalType) -> Layout {
2173
    match info {
2174
        case NominalType::Placeholder(_) => {
2175
            panic "getNominalLayout: placeholder type";
2176
        }
2177
        case NominalType::Record(recordType) => {
2178
            return recordType.layout;
2179
        }
2180
        case NominalType::Union(unionType) => {
2181
            return unionType.layout;
2182
        }
2183
    }
2184
}
2185
2186
/// Get the layout of a result aggregate with a tag and the larger payload.
2187
export fn getResultLayout(payload: Type, throwList: *[*Type]) -> Layout {
2188
    let payloadLayout = getTypeLayout(payload);
2189
    let mut maxSize = payloadLayout.size;
2190
    let mut maxAlign = payloadLayout.alignment;
2191
2192
    for errType in throwList {
2193
        let errLayout = getTypeLayout(*errType);
2194
        set maxSize = max(maxSize, errLayout.size);
2195
        set maxAlign = max(maxAlign, errLayout.alignment);
2196
    }
2197
    return Layout {
2198
        size: PTR_SIZE + maxSize,
2199
        alignment: max(PTR_SIZE, maxAlign),
2200
    };
2201
}
2202
2203
/// Compute the layout for a union given its resolved variants.
2204
fn computeUnionLayout(variants: *[UnionVariant]) -> UnionLayoutInfo {
2205
    let tagSize: u32 = 1;
2206
    let mut maxVarSize: u32 = 0;
2207
    let mut maxVarAlign: u32 = 1;
2208
    let mut isAllVoid: bool = true;
2209
2210
    for variant in variants {
2211
        if variant.valueType <> Type::Void {
2212
            set isAllVoid = false;
2213
            let payloadLayout = getTypeLayout(variant.valueType);
2214
            set maxVarSize = max(maxVarSize, payloadLayout.size);
2215
            set maxVarAlign = max(maxVarAlign, payloadLayout.alignment);
2216
        }
2217
    }
2218
    let unionAlignment: u32 = max(1, maxVarAlign);
2219
    let unionValOffset: u32 = mem::alignUp(tagSize, maxVarAlign);
2220
    let unionLayout = Layout {
2221
        size: mem::alignUp(unionValOffset + maxVarSize, unionAlignment),
2222
        alignment: unionAlignment,
2223
    };
2224
    return UnionLayoutInfo { layout: unionLayout, valOffset: unionValOffset, isAllVoid };
2225
}
2226
2227
/// Compute the discriminant tag for a variant, advancing the iota counter.
2228
fn variantTag(
2229
    self: *mut Resolver,
2230
    variantDecl: ast::UnionDeclVariant,
2231
    iota: *mut u32,
2232
    sub: ?*Substitution,
2233
) -> u32 throws (ResolveError) {
2234
    let mut tag: u32 = *iota;
2235
    if let valueNode = variantDecl.value {
2236
        let mut value: ?ConstValue = nil;
2237
        if let substitution = sub {
2238
            set value = constValueWithSubstitution(self, valueNode, substitution);
2239
        } else {
2240
            set value = constValueEntry(self, valueNode);
2241
        }
2242
        let resolved = value
2243
            else throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
2244
        if not validateConstIntRange(resolved, Type::U32) {
2245
            throw emitError(self, valueNode, ErrorKind::NumericLiteralOverflow);
2246
        }
2247
        let case ConstValue::Int(int) = resolved
2248
            else throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
2249
        set tag = int.magnitude as u32;
2250
    }
2251
    set *iota = tag + 1;
2252
    return tag;
2253
}
2254
2255
/// Check if a type is a union without payloads.
2256
export fn isVoidUnion(ty: Type) -> bool {
2257
    let case Type::Nominal(NominalType::Union(unionType)) = ty
2258
        else return false;
2259
    return unionType.isAllVoid;
2260
}
2261
2262
/// Check if a type should be treated as an address-like value.
2263
fn isAddressType(ty: Type) -> bool {
2264
    match ty {
2265
        case Type::Pointer(_), Type::Slice(_), Type::Fn(_) => return true,
2266
        else => return false,
2267
    }
2268
}
2269
2270
/// Return the representable range for an integer type.
2271
fn integerRange(ty: Type) -> ?IntegerRange {
2272
    match ty {
2273
        case Type::I8 => return IntegerRange::Signed {
2274
            bits: 8,
2275
            min: I8_MIN as i64,
2276
            max: I8_MAX as i64,
2277
            lim: (I8_MAX as u64) + 1,
2278
        },
2279
        case Type::I16 => return IntegerRange::Signed {
2280
            bits: 16,
2281
            min: I16_MIN as i64,
2282
            max: I16_MAX as i64,
2283
            lim: (I16_MAX as u64) + 1,
2284
        },
2285
        case Type::I32 => return IntegerRange::Signed {
2286
            bits: 32,
2287
            min: I32_MIN as i64,
2288
            max: I32_MAX as i64,
2289
            lim: (I32_MAX as u64) + 1,
2290
        },
2291
        case Type::I64, Type::Int => return IntegerRange::Signed {
2292
            bits: 64,
2293
            min: I64_MIN,
2294
            max: I64_MAX,
2295
            lim: (I64_MAX as u64) + 1,
2296
        },
2297
        case Type::U8 => return IntegerRange::Unsigned { bits: 8, max: U8_MAX as u64 },
2298
        case Type::U16 => return IntegerRange::Unsigned { bits: 16, max: U16_MAX as u64 },
2299
        case Type::U32 => return IntegerRange::Unsigned { bits: 32, max: parser::U32_MAX as u64 },
2300
        case Type::U64 => return IntegerRange::Unsigned { bits: 64, max: parser::U64_MAX },
2301
        else => return nil,
2302
    }
2303
}
2304
2305
/// Validate that an integer constant fits within the target type's range.
2306
fn validateConstIntRange(value: ConstValue, target: Type) -> bool {
2307
    let range = integerRange(target)
2308
        else panic "validateConstIntRange: expected integer type";
2309
    let case ConstValue::Int(int) = value
2310
        else panic "validateConstIntRange: expected integer constant";
2311
2312
    match range {
2313
        case IntegerRange::Signed { lim, .. } => {
2314
            if int.negative {
2315
                if int.magnitude > lim {
2316
                    return false;
2317
                }
2318
                return true;
2319
            }
2320
            if int.magnitude > lim - 1 {
2321
                return false;
2322
            }
2323
            return true;
2324
        }
2325
        case IntegerRange::Unsigned { max, .. } => {
2326
            if int.negative or int.magnitude > max {
2327
                return false;
2328
            }
2329
            return true;
2330
        }
2331
    }
2332
}
2333
2334
/// Ensure all nested nominal types in a type are resolved.
2335
fn ensureTypeResolved(self: *mut Resolver, ty: Type, site: *ast::Node) throws (ResolveError) {
2336
    match ty {
2337
        case Type::Nominal(info) => try ensureNominalResolved(self, info, site),
2338
        case Type::Slice(slice) => try ensureTypeResolved(self, *slice.item, site),
2339
        case Type::Pointer(_) => {}, // Pointers have fixed layout, don't recurse.
2340
        case Type::Array(arr) => try ensureTypeResolved(self, *arr.item, site),
2341
        case Type::Optional(inner) => try ensureTypeResolved(self, *inner, site),
2342
        else => {},
2343
    }
2344
}
2345
2346
/// Ensure a nominal type has its body resolved.
2347
fn ensureNominalResolved(self: *mut Resolver, tyInfo: *NominalType, site: *ast::Node)
2348
    throws (ResolveError)
2349
{
2350
    if let case NominalType::Placeholder(declNode) = *tyInfo {
2351
        // When resolving on-demand (e.g. from a child module), switch to the
2352
        // declaring module's scope so field type lookups find the right symbols.
2353
        let prevScope = self.scope;
2354
        let prevMod = self.currentMod;
2355
2356
        if let sym = symbolFor(self, declNode) {
2357
            if let mid = sym.moduleId {
2358
                if (mid as u32) < self.moduleScopes.len {
2359
                    if let ms = self.moduleScopes[mid as u32] {
2360
                        set self.scope = ms;
2361
                        set self.currentMod = mid;
2362
                    }
2363
                }
2364
            }
2365
        }
2366
2367
        match declNode.value {
2368
            case ast::NodeValue::RecordDecl(decl) => {
2369
                try resolveRecordBody(self, declNode, decl);
2370
            }
2371
            case ast::NodeValue::UnionDecl(decl) => {
2372
                try resolveUnionBody(self, declNode, decl);
2373
            }
2374
            else => {},
2375
        }
2376
        set self.scope = prevScope;
2377
        set self.currentMod = prevMod;
2378
    }
2379
}
2380
2381
/// Check if all elements in a node list are assignable to the target type.
2382
fn isListAssignable(self: *mut Resolver, targetType: Type, items: *mut [*ast::Node]) -> bool {
2383
    for itemNode in items {
2384
        let elemTy = typeFor(self, itemNode)
2385
            else return false;
2386
        if let _ = isAssignable(self, targetType, elemTy, itemNode) {
2387
            // Do nothing.
2388
        } else {
2389
            return false;
2390
        }
2391
    }
2392
    return true;
2393
}
2394
2395
/// Preserve legacy address-of coercions until a package opts into linearity.
2396
fn pointerClassesAssignable(
2397
    self: *Resolver,
2398
    to: types::PointerClass,
2399
    from: types::PointerClass,
2400
) -> bool {
2401
    return to == from or (
2402
        not self.linearEnabled
2403
        and to == types::PointerClass::Owned
2404
        and from == types::PointerClass::Ref
2405
    );
2406
}
2407
2408
/// Check if the `from` type is assignable to the `to` type, and return a
2409
/// coercion plan if so.
2410
fn isAssignable(self: *mut Resolver, to: Type, from: Type, rval: *ast::Node) -> ?Coercion {
2411
    if to == Type::Unknown or from == Type::Unknown {
2412
        return nil;
2413
    }
2414
    if from == Type::Undefined {
2415
        // TODO: Don't let `undefined` be used in place of functions and other
2416
        // non-data types.
2417
        return Coercion::Identity;
2418
    }
2419
    // The "never" type can always be assigned, since the code path is never
2420
    // executed.
2421
    if from == Type::Never {
2422
        return Coercion::Identity;
2423
    }
2424
    if typesEqual(to, from) {
2425
        return Coercion::Identity;
2426
    }
2427
    if let case Type::Pointer(lhs) = to {
2428
        let case Type::Pointer(rhs) = from else return nil;
2429
        if not pointerClassesAssignable(self, lhs.class, rhs.class) {
2430
            return nil;
2431
        }
2432
        // Allow coercion from `*T` to `*opaque`, and mutable counterparts.
2433
        if *lhs.target == Type::Opaque {
2434
            if lhs.mutable and not rhs.mutable {
2435
                return nil;
2436
            }
2437
            return Coercion::Identity;
2438
        }
2439
        if lhs.mutable and not rhs.mutable {
2440
            return nil;
2441
        }
2442
        return isAssignable(self, *lhs.target, *rhs.target, rval);
2443
    }
2444
    if let case Type::TraitObject(lhs) = to {
2445
        if let case Type::Pointer(rhs) = from {
2446
            if not pointerClassesAssignable(self, lhs.class, rhs.class)
2447
                or (lhs.mutable and not rhs.mutable)
2448
            {
2449
                return nil;
2450
            }
2451
            if let inst = findInstance(self, lhs.traitInfo, *rhs.target) {
2452
                return Coercion::TraitObject { traitInfo: lhs.traitInfo, inst };
2453
            }
2454
        }
2455
        if let case Type::TraitObject(rhs) = from {
2456
            if not pointerClassesAssignable(self, lhs.class, rhs.class)
2457
                or lhs.traitInfo <> rhs.traitInfo
2458
            {
2459
                return nil;
2460
            }
2461
            if lhs.mutable and not rhs.mutable {
2462
                return nil;
2463
            }
2464
            return Coercion::Identity;
2465
        }
2466
        return nil;
2467
    }
2468
    if let case Type::Slice(lhs) = to {
2469
        let case Type::Slice(rhs) = from else return nil;
2470
        if not pointerClassesAssignable(self, lhs.class, rhs.class)
2471
            or (lhs.mutable and not rhs.mutable)
2472
        {
2473
            return nil;
2474
        }
2475
        // Allow coercion from `*[T]` to `*[opaque]`, and mutable counterparts.
2476
        if *lhs.item == Type::Opaque {
2477
            return Coercion::Identity;
2478
        }
2479
        return isAssignable(self, *lhs.item, *rhs.item, rval);
2480
    }
2481
    match to {
2482
        case Type::Array(lhs) => {
2483
            let case Type::Array(rhs) = from
2484
                else return nil;
2485
2486
            if lhs.length <> rhs.length {
2487
                return nil;
2488
            }
2489
            // For array literals, check each element individually for
2490
            // assignability.
2491
            match rval.value {
2492
                case ast::NodeValue::ArrayLit(items) => {
2493
                    if rhs.length == 0 and lhs.length == 0 {
2494
                        return Coercion::Identity;
2495
                    }
2496
                    // TODO: This won't work, because we should be setting coercions
2497
                    // for every list item, but we don't. It's best to not have an
2498
                    // `isAssignable` function and just have one that records coercions.
2499
                    if isListAssignable(self, *lhs.item, items) {
2500
                        return Coercion::Identity;
2501
                    }
2502
                    return nil;
2503
                }
2504
                case ast::NodeValue::ArrayRepeatLit(repeat) => {
2505
                    return isAssignable(self, *lhs.item, *rhs.item, repeat.item);
2506
                }
2507
                else => {
2508
                    if typesEqual(*lhs.item, *rhs.item) {
2509
                        return Coercion::Identity;
2510
                    }
2511
                    return nil;
2512
                }
2513
            }
2514
        }
2515
2516
        case Type::Optional(inner) => {
2517
            if from == Type::Nil {
2518
                return Coercion::OptionalLift(to);
2519
            }
2520
            if let _ = isAssignable(self, *inner, from, rval) {
2521
                return Coercion::OptionalLift(to);
2522
            }
2523
            if let case Type::Optional(fromInner) = from {
2524
                return isAssignable(self, *inner, *fromInner, rval);
2525
            }
2526
            return nil;
2527
        }
2528
2529
        case Type::Fn(toInfo) => {
2530
            // Allow function type structural matching.
2531
            if let case Type::Fn(fromInfo) = from {
2532
                if fnTypeEqual(toInfo, fromInfo) {
2533
                    return Coercion::Identity;
2534
                }
2535
            }
2536
            return nil;
2537
        }
2538
        else => {
2539
            if isNumericType(to) and isNumericType(from) {
2540
                // Perform range validation at compile time if possible.
2541
                // For unsuffixed integer expressions (`Type::Int`), only
2542
                // validate literals directly written by the programmer.
2543
                // Folded results (e.g. `0 - 65`) may not fit the target
2544
                // type but are valid wrapping arithmetic at runtime.
2545
                if let value = constValueEntry(self, rval) {
2546
                    if from <> Type::Int or isIntegerLiteralExpr(rval) {
2547
                        if validateConstIntRange(value, to) {
2548
                            return Coercion::Identity;
2549
                        }
2550
                        return nil;
2551
                    }
2552
                    // Folded constant expression (e.g. `1 + 2`): if the
2553
                    // result fits the target, use identity. Otherwise allow
2554
                    // wrapping via numeric cast.
2555
                    if validateConstIntRange(value, to) {
2556
                        return Coercion::Identity;
2557
                    }
2558
                }
2559
                // Allow unsuffixed integer expressions to be inferred from context.
2560
                if from == Type::Int {
2561
                    return Coercion::NumericCast { from, to };
2562
                }
2563
                // Non-constant numeric values require an explicit cast.
2564
                return nil;
2565
            }
2566
        }
2567
    }
2568
    return nil;
2569
}
2570
2571
/// Check if two function type descriptors are structurally equivalent.
2572
fn fnTypeEqual(a: *FnType, b: *FnType) -> bool {
2573
    if a.isUnsafe <> b.isUnsafe {
2574
        return false;
2575
    }
2576
    if a.paramTypes.len <> b.paramTypes.len {
2577
        return false;
2578
    }
2579
    if a.throwList.len <> b.throwList.len {
2580
        return false;
2581
    }
2582
    if not typesEqual(*a.returnType, *b.returnType) {
2583
        return false;
2584
    }
2585
    for i in 0..a.paramTypes.len {
2586
        if not typesEqual(*a.paramTypes[i], *b.paramTypes[i]) {
2587
            return false;
2588
        }
2589
    }
2590
    for i in 0..a.throwList.len {
2591
        if not typesEqual(*a.throwList[i], *b.throwList[i]) {
2592
            return false;
2593
        }
2594
    }
2595
    return true;
2596
}
2597
2598
/// Check if two types are structurally equal.
2599
export fn typesEqual(a: Type, b: Type) -> bool {
2600
    if a == b {
2601
        return true;
2602
    }
2603
    if let case Type::Pointer(av) = a {
2604
        let case Type::Pointer(bv) = b else return false;
2605
        return av.class == bv.class and av.mutable == bv.mutable
2606
            and typesEqual(*av.target, *bv.target);
2607
    }
2608
    if let case Type::Slice(av) = a {
2609
        let case Type::Slice(bv) = b else return false;
2610
        return av.class == bv.class and av.mutable == bv.mutable
2611
            and typesEqual(*av.item, *bv.item);
2612
    }
2613
    if let case Type::TraitObject(av) = a {
2614
        let case Type::TraitObject(bv) = b else return false;
2615
        return av.class == bv.class and av.mutable == bv.mutable
2616
            and av.traitInfo == bv.traitInfo;
2617
    }
2618
    match a {
2619
        case Type::Array(aa) => {
2620
            let case Type::Array(ab) = b else return false;
2621
            return aa.length == ab.length and typesEqual(*aa.item, *ab.item);
2622
        }
2623
        case Type::Optional(oa) => {
2624
            let case Type::Optional(ob) = b else return false;
2625
            return typesEqual(*oa, *ob);
2626
        }
2627
        case Type::Fn(fa) => {
2628
            let case Type::Fn(fb) = b else return false;
2629
            return fnTypeEqual(fa, fb);
2630
        }
2631
        case Type::GenericDataApply(aa) => {
2632
            let case Type::GenericDataApply(ab) = b else return false;
2633
            if aa.template <> ab.template or aa.args.len <> ab.args.len {
2634
                return false;
2635
            }
2636
            for i in 0..aa.args.len {
2637
                if not typesEqual(*aa.args[i], *ab.args[i]) {
2638
                    return false;
2639
                }
2640
            }
2641
            return true;
2642
        }
2643
        else => return false,
2644
    }
2645
}
2646
2647
/// Return whether `ty` is a direct reference.
2648
export fn isRefType(ty: Type) -> bool {
2649
    match ty {
2650
        case Type::Pointer(PointerType { class: types::PointerClass::Ref, .. }),
2651
             Type::Slice(SliceType { class: types::PointerClass::Ref, .. }),
2652
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Ref, .. }) => return true,
2653
        else => return false,
2654
    }
2655
}
2656
2657
/// Return whether a type contains a reference.
2658
fn containsRef(ty: Type) -> bool {
2659
    if isRefType(ty) {
2660
        return true;
2661
    }
2662
    if let case Type::Pointer(pointer) = ty {
2663
        return containsRef(*pointer.target);
2664
    }
2665
    if let case Type::Slice(slice) = ty {
2666
        return containsRef(*slice.item);
2667
    }
2668
    match ty {
2669
        case Type::Array(array) => return containsRef(*array.item),
2670
        case Type::Optional(inner) => return containsRef(*inner),
2671
        case Type::GenericRecord(rec) => {
2672
            for field in rec.fields {
2673
                if containsRef(field.fieldType) {
2674
                    return true;
2675
                }
2676
            }
2677
            return false;
2678
        }
2679
        // Nominal declarations validate their own fields and variants.
2680
        // Treating them as leaves also terminates recursive pointer types.
2681
        case Type::Nominal(_) => return false,
2682
        else => return false,
2683
    }
2684
}
2685
2686
/// Return whether a type is exact-linear.
2687
export fn isLinear(ty: Type) -> bool {
2688
    match ty {
2689
        case Type::Pointer(PointerType { class: types::PointerClass::Owned, .. }),
2690
             Type::Slice(SliceType { class: types::PointerClass::Owned, .. }),
2691
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Owned, .. }) => return true,
2692
        case Type::Pointer(PointerType { class: types::PointerClass::Ref, .. }),
2693
             Type::Pointer(PointerType { class: types::PointerClass::Unsafe, .. }),
2694
             Type::Slice(SliceType { class: types::PointerClass::Ref, .. }),
2695
             Type::Slice(SliceType { class: types::PointerClass::Unsafe, .. }),
2696
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Ref, .. }),
2697
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Unsafe, .. }) => return false,
2698
2699
        case Type::Array(array) => return isLinear(*array.item),
2700
        case Type::Optional(inner) => return isLinear(*inner),
2701
        case Type::Nominal(NominalType::Record(recInfo)) => {
2702
            if recInfo.declaredLinear {
2703
                return true;
2704
            }
2705
            for field in recInfo.fields {
2706
                if isLinear(field.fieldType) {
2707
                    return true;
2708
                }
2709
            }
2710
            return false;
2711
        }
2712
        case Type::Nominal(NominalType::Union(unionType)) => {
2713
            if unionType.declaredLinear {
2714
                return true;
2715
            }
2716
            for variant in unionType.variants {
2717
                if isLinear(variant.valueType) {
2718
                    return true;
2719
                }
2720
            }
2721
            return false;
2722
        }
2723
        else => return false,
2724
    }
2725
}
2726
2727
/// Return whether `ty` is a direct unsafe pointer-like value.
2728
fn isUnsafePointerType(ty: Type) -> bool {
2729
    match ty {
2730
        case Type::Pointer(PointerType { class: types::PointerClass::Unsafe, .. }),
2731
             Type::Slice(SliceType { class: types::PointerClass::Unsafe, .. }),
2732
             Type::TraitObject(TraitObjectType { class: types::PointerClass::Unsafe, .. }) => return true,
2733
        else => return false,
2734
    }
2735
}
2736
2737
/// Get the record info from a record type.
2738
export fn getRecord(ty: Type) -> ?RecordType {
2739
    let case Type::Nominal(NominalType::Record(recInfo)) = ty else return nil;
2740
    return recInfo;
2741
}
2742
2743
/// Auto-dereference a type: if it's a pointer, return the target type.
2744
export fn autoDeref(ty: Type) -> Type {
2745
    if let case Type::Pointer(view) = ty {
2746
        return *view.target;
2747
    }
2748
    return ty;
2749
}
2750
2751
/// Get field info for a record-like type (records, slices) by field index.
2752
export fn getRecordField(ty: Type, index: u32) -> ?RecordField {
2753
    if let case Type::Slice(slice) = ty {
2754
        match index {
2755
            case 0 => return RecordField {
2756
                name: PTR_FIELD,
2757
                fieldType: Type::Pointer(PointerType {
2758
                    class: slice.class,
2759
                    target: slice.item,
2760
                    mutable: slice.mutable,
2761
                }),
2762
                offset: 0,
2763
            },
2764
            case 1 => return RecordField {
2765
                name: LEN_FIELD,
2766
                fieldType: Type::U32,
2767
                offset: PTR_SIZE as i32,
2768
            },
2769
            case 2 => return RecordField {
2770
                name: CAP_FIELD,
2771
                fieldType: Type::U32,
2772
                offset: PTR_SIZE as i32 + 4,
2773
            },
2774
            else => return nil,
2775
        }
2776
    }
2777
    if let case Type::Nominal(NominalType::Record(recInfo)) = ty;
2778
        index < recInfo.fields.len
2779
    {
2780
        return recInfo.fields[index];
2781
    }
2782
    return nil;
2783
}
2784
2785
/// Check if the two types can be compared for equality.
2786
fn isComparable(left: Type, right: Type) -> bool {
2787
    if left == Type::Unknown or right == Type::Unknown {
2788
        return false;
2789
    }
2790
    if left == right {
2791
        return true;
2792
    }
2793
    // Comparisons with optionals.
2794
    if let case Type::Optional(l) = left {
2795
        if let case Type::Optional(r) = right {
2796
            return isComparable(*l, *r);
2797
        } else if right == Type::Nil {
2798
            return true;
2799
        }
2800
        return isComparable(*l, right);
2801
    } else if let case Type::Optional(_) = right {
2802
        return isComparable(right, left); // Flip order.
2803
    }
2804
    // Pointer comparisons ignore mutability.
2805
    if let case Type::Pointer(l) = left {
2806
        if let case Type::Pointer(r) = right {
2807
            return typesEqual(*l.target, *r.target);
2808
        }
2809
    }
2810
    // Numeric types.
2811
    if isNumericType(left) and isNumericType(right) {
2812
        return true;
2813
    }
2814
    return false;
2815
}
2816
2817
/// Check if the `from` type is assignable to the `to` type, and return a
2818
/// coercion plan if so, or throw an error if not.
2819
fn expectAssignable(self: *mut Resolver, to: Type, from: Type, site: *ast::Node) -> Coercion throws (ResolveError) {
2820
    // Ensure any nested nominal types are resolved before checking assignability.
2821
    try ensureTypeResolved(self, to, site);
2822
    if let coercion = isAssignable(self, to, from, site) {
2823
        return setNodeCoercion(self, site, coercion);
2824
    }
2825
    throw emitTypeMismatch(self, site, TypeMismatch {
2826
        expected: to,
2827
        actual: from,
2828
    });
2829
}
2830
2831
/// Check that a type is optional, otherwise throw an error.
2832
fn checkOptional(self: *mut Resolver, node: *ast::Node) -> *Type
2833
    throws (ResolveError)
2834
{
2835
    if let case Type::Optional(inner) = try infer(self, node) {
2836
        return inner;
2837
    }
2838
    throw emitError(self, node, ErrorKind::ExpectedOptional);
2839
}
2840
2841
/// Check that a node's type is equal to the expected type.
2842
fn checkEqual(self: *mut Resolver, node: *ast::Node, expected: Type) -> Type
2843
    throws (ResolveError)
2844
{
2845
    let actualTy = try visit(self, node, expected);
2846
    if actualTy <> expected {
2847
        throw emitTypeMismatch(self, node, TypeMismatch { expected, actual: actualTy });
2848
    }
2849
    return actualTy;
2850
}
2851
2852
/// Bind an identifier in the given scope.
2853
fn bindIdent(
2854
    self: *mut Resolver,
2855
    name: *[u8],
2856
    owner: *ast::Node,
2857
    data: SymbolData,
2858
    attrs: u32,
2859
    scope: *mut Scope
2860
) -> *mut Symbol throws (ResolveError) {
2861
    let sym = allocSymbol(self, data, name, owner, attrs);
2862
    try addSymbolToScope(self, sym, scope, owner);
2863
    setNodeSymbol(self, owner, sym);
2864
2865
    return sym;
2866
}
2867
2868
/// Add a symbol to the given scope.
2869
fn addSymbolToScope(self: *mut Resolver, sym: *mut Symbol, scope: *mut Scope, site: *ast::Node) throws (ResolveError) {
2870
    for i in 0..scope.symbolsLen {
2871
        if scope.symbols[i].name == sym.name {
2872
            throw emitError(self, site, ErrorKind::DuplicateBinding(sym.name));
2873
        }
2874
    }
2875
    if scope.symbolsLen >= scope.symbols.len {
2876
        throw emitError(self, site, ErrorKind::SymbolOverflow);
2877
    }
2878
    // Preserve the defining module when importing an existing symbol into
2879
    // another module's scope.
2880
    if sym.moduleId == nil {
2881
        if let modId = scope.moduleId {
2882
            set sym.moduleId = modId;
2883
        }
2884
    }
2885
    set scope.symbols[scope.symbolsLen] = sym;
2886
    set scope.symbolsLen += 1;
2887
}
2888
2889
/// Bind a value identifier in the current scope.
2890
/// Returns `nil` if the identifier is a placeholder (`_`).
2891
fn bindValueIdent(
2892
    self: *mut Resolver,
2893
    ident: *ast::Node,
2894
    owner: *ast::Node,
2895
    type: Type,
2896
    mutable: bool,
2897
    alignment: u32,
2898
    attrs: u32
2899
) -> ?*mut Symbol throws (ResolveError) {
2900
    if let case ast::NodeValue::Placeholder = ident.value {
2901
        setNodeType(self, owner, type);
2902
        return nil;
2903
    }
2904
    let name = try nodeName(self, ident);
2905
    let data = SymbolData::Value { mutable, alignment, type, addressTaken: false };
2906
    let sym = try bindIdent(self, name, owner, data, attrs, self.scope);
2907
    setNodeType(self, owner, type);
2908
    setNodeType(self, ident, type);
2909
2910
    // Track number of local bindings for lowering stage.
2911
    if let mut fnType = self.currentFn {
2912
        set fnType.localCount += 1;
2913
    }
2914
    return sym;
2915
}
2916
2917
/// Bind a constant identifier in the current scope.
2918
fn bindConstIdent(
2919
    self: *mut Resolver,
2920
    ident: *ast::Node,
2921
    owner: *ast::Node,
2922
    type: Type,
2923
    val: ?ConstValue,
2924
    attrs: u32
2925
) -> *mut Symbol throws (ResolveError) {
2926
    let name = try nodeName(self, ident);
2927
    let data = SymbolData::Constant { type, value: val };
2928
    let sym = try bindIdent(self, name, owner, data, attrs, self.scope);
2929
    setNodeType(self, owner, type);
2930
    setNodeType(self, ident, type);
2931
2932
    return sym;
2933
}
2934
2935
/// Bind a module identifier in the given scope.
2936
/// This is used when declaring modules with `mod` or
2937
/// importing modules with `use`.
2938
fn bindModuleIdent(
2939
    self: *mut Resolver,
2940
    entry: *module::ModuleEntry,
2941
    scope: *mut Scope,
2942
    owner: *ast::Node,
2943
    attrs: u32,
2944
    bindingScope: *mut Scope
2945
) -> *mut Symbol throws (ResolveError) {
2946
    let data = SymbolData::Module { entry, scope };
2947
    let name = entry.name;
2948
2949
    return try bindIdent(self, name, owner, data, attrs, bindingScope);
2950
}
2951
2952
/// Bind a type identifier in the current scope.
2953
fn bindTypeIdent(
2954
    self: *mut Resolver,
2955
    ident: *ast::Node,
2956
    owner: *ast::Node,
2957
    type: *mut NominalType,
2958
    attrs: u32
2959
) -> *mut Symbol throws (ResolveError) {
2960
    let name = try nodeName(self, ident);
2961
    let data = SymbolData::Type(type);
2962
    return try bindIdent(self, name, owner, data, attrs, self.scope);
2963
}
2964
2965
/// Predicate that matches any symbol.
2966
fn isAnySymbol(_sym: *mut Symbol) -> bool {
2967
    return true;
2968
}
2969
2970
/// Predicate that matches value or constant symbols.
2971
fn isValueSymbol(sym: *mut Symbol) -> bool {
2972
    if let case SymbolData::Value { .. } = sym.data {
2973
        return true;
2974
    }
2975
    if let case SymbolData::Constant { .. } = sym.data {
2976
        return true;
2977
    }
2978
    return false;
2979
}
2980
2981
/// Predicate that matches type symbols.
2982
fn isTypeSymbol(sym: *mut Symbol) -> bool {
2983
    match sym.data {
2984
        case SymbolData::Type(_), SymbolData::TypeParameter(_) => return true,
2985
        else => return false,
2986
    }
2987
}
2988
2989
/// Find a symbol by name in a specific scope, filtered by a predicate.
2990
fn findInScope(scope: *Scope, name: *[u8], predicate: fn(*mut Symbol) -> bool) -> ?*mut Symbol {
2991
    for i in 0..scope.symbolsLen {
2992
        let sym = scope.symbols[i];
2993
        if sym.name == name and predicate(sym) {
2994
            return sym;
2995
        }
2996
    }
2997
    return nil;
2998
}
2999
3000
/// Find a symbol by name, traversing scopes upwards, filtered by a predicate.
3001
fn findInScopeRecursive(scope: *Scope, name: *[u8], predicate: fn(*mut Symbol) -> bool) -> ?*mut Symbol {
3002
    let mut curr = scope;
3003
    loop {
3004
        if let sym = findInScope(curr, name, predicate) {
3005
            return sym;
3006
        }
3007
        if let parent = curr.parent {
3008
            set curr = parent;
3009
        } else {
3010
            break;
3011
        }
3012
    }
3013
    return nil;
3014
}
3015
3016
/// Find a symbol by name in a specific scope (matches any symbol kind).
3017
export fn findSymbolInScope(scope: *Scope, name: *[u8]) -> ?*mut Symbol {
3018
    return findInScope(scope, name, isAnySymbol);
3019
}
3020
3021
/// Look up a value symbol by name, searching from the given scope outward.
3022
fn findValueSymbol(scope: *Scope, name: *[u8]) -> ?*mut Symbol {
3023
    return findInScopeRecursive(scope, name, isValueSymbol);
3024
}
3025
3026
/// Look up a type symbol by name, searching from the given scope outward.
3027
fn findTypeSymbol(scope: *Scope, name: *[u8]) -> ?*mut Symbol {
3028
    return findInScopeRecursive(scope, name, isTypeSymbol);
3029
}
3030
3031
/// Like `findValueSymbol`, but finds symbols of any kinds.
3032
fn findAnySymbol(scope: *Scope, name: *[u8]) -> ?*mut Symbol {
3033
    return findInScopeRecursive(scope, name, isAnySymbol);
3034
}
3035
3036
/// Flatten an identifier or scope access chain into an array of name segments.
3037
/// Examples: `fnord` -> `&["fnord"]`, `a::b::c` -> `&["a", "b", "c"]`.
3038
/// Returns a slice of the segments that were written.
3039
fn flattenPath(
3040
    self: *mut Resolver,
3041
    node: *ast::Node,
3042
    buf: *mut [*[u8]]
3043
) -> *[*[u8]] throws (ResolveError) {
3044
    let mut out: *[*[u8]] = &[];
3045
3046
    match node.value {
3047
        case ast::NodeValue::Ident(name) if name.len > 0 => {
3048
            assert buf.len >= 1, "flattenPath: invalid output buffer size";
3049
            set buf[0] = name;
3050
            set out = &buf[..1];
3051
        }
3052
        case ast::NodeValue::ScopeAccess(access) => {
3053
            // Recursively flatten parent path.
3054
            let parent = try flattenPath(self, access.parent, buf);
3055
            assert parent.len < buf.len, "flattenPath: invalid output buffer size";
3056
            let child = try nodeName(self, access.child);
3057
            set buf[parent.len] = child;
3058
            set out = &buf[..parent.len + 1];
3059
        }
3060
        case ast::NodeValue::Super => {
3061
            // `super` is handled by scope adjustment in `checkSuperAccess`.
3062
            // Return empty prefix so the path continues from the next segment.
3063
            set out = &buf[..0];
3064
            return out;
3065
        }
3066
        else => {
3067
            // Fallthrough to error.
3068
        }
3069
    }
3070
    if out.len < 1 {
3071
        throw emitError(self, node, ErrorKind::InvalidIdentifier(node));
3072
    }
3073
    return out;
3074
}
3075
3076
/// Find the module ID for a given scope by walking up the scope chain until
3077
/// we hit the module's scope.
3078
fn findModuleForScope(scope: *Scope) -> ?u16 {
3079
    let mut s = scope;
3080
    loop {
3081
        if let id = s.moduleId {
3082
            return id;
3083
        }
3084
        if let parent = s.parent {
3085
            set s = parent;
3086
        } else {
3087
            return nil;
3088
        }
3089
    }
3090
}
3091
3092
/// Get the parent module scope for the current module.
3093
/// Returns the scope of the parent module, or `nil` if this is a root module.
3094
fn getParentModuleScope(self: *mut Resolver, node: *ast::Node) -> ?*mut Scope throws (ResolveError) {
3095
    let currentMod = module::get(self.moduleGraph, self.currentMod)
3096
        else throw emitError(self, node, ErrorKind::Internal);
3097
    let parentId = currentMod.parent
3098
        else return nil; // No parent module.
3099
3100
    return self.moduleScopes[parentId as u32];
3101
}
3102
3103
/// Check if a node has `super` at its root (e.g. `super::x` or `super::Union::Variant`).
3104
/// Returns the parent scope and the original node so `flattenPath` can strip `super`.
3105
fn checkSuperAccess(
3106
    self: *mut Resolver,
3107
    node: *ast::Node
3108
) -> ?SuperAccessResult throws (ResolveError) {
3109
    // TODO: Maybe we should deal with `super` after the path is flattened.
3110
    if let case ast::NodeValue::ScopeAccess(access) = node.value {
3111
        // Direct super access: `super::x`.
3112
        if let case ast::NodeValue::Super = access.parent.value {
3113
            let parentScope = try getParentModuleScope(self, node)
3114
                else throw emitError(self, node, ErrorKind::InvalidModulePath);
3115
            return SuperAccessResult { scope: parentScope, child: node };
3116
        }
3117
        // Nested super access: `super::x::y`, check if parent path contains `super`.
3118
        if let _ = try checkSuperAccess(self, access.parent) {
3119
            let parentScope = try getParentModuleScope(self, node)
3120
                else throw emitError(self, node, ErrorKind::InvalidModulePath);
3121
            return SuperAccessResult { scope: parentScope, child: node };
3122
        }
3123
    }
3124
    return nil;
3125
}
3126
3127
/// Check if a symbol is accessible from the given scope.
3128
/// A symbol is accessible if:
3129
/// * It has the `export` attribute, OR
3130
/// * It's being accessed from within the module where it was defined.
3131
fn isSymbolVisible(sym: *Symbol, symScope: *Scope, fromScope: *Scope) -> bool {
3132
    // Public symbols are visible from anywhere.
3133
    if ast::hasAttribute(sym.attrs, ast::Attribute::Export) {
3134
        return true;
3135
    }
3136
    // In test mode, @test symbols are visible from anywhere
3137
    // so the test runner can reference them.
3138
    if ast::hasAttribute(sym.attrs, ast::Attribute::Test) {
3139
        return true;
3140
    }
3141
    // Private symbols are only visible from the same module.
3142
    let symModuleId = findModuleForScope(symScope);
3143
    let currentModuleId = findModuleForScope(fromScope);
3144
3145
    return symModuleId == currentModuleId;
3146
}
3147
3148
/// Resolve an access node (eg. `lang::resolver::MAX_ERRORS`) to a symbol,
3149
/// starting from the given scope.
3150
fn resolveAccess(
3151
    self: *mut Resolver,
3152
    node: *ast::Node,
3153
    access: ast::Access,
3154
    scope: *Scope
3155
) -> *mut Symbol throws (ResolveError) {
3156
    // A specialized union application introduces the variant namespace.
3157
    if let case ast::NodeValue::GenericApply(app) = access.parent.value {
3158
        let nominal = try resolveGenericDataApply(self, access.parent, app, false);
3159
        let case NominalType::Union(unionType) = *nominal
3160
            else throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3161
        let variantName = try nodeName(self, access.child);
3162
        let variant = try resolveUnionVariantAccess(
3163
            self, node, access, unionType, variantName
3164
        );
3165
        setNodeType(self, node, Type::Nominal(nominal));
3166
        return variant;
3167
    }
3168
    let mut startScope = scope;
3169
    let mut pathNode = node;
3170
    if let superAccess = try checkSuperAccess(self, node) {
3171
        set startScope = superAccess.scope;
3172
        set pathNode = superAccess.child;
3173
    }
3174
    // TODO: It doesn't make sense that `flattenPath` handles identifiers and scope access,
3175
    // while this function requires a scope access.
3176
    let mut buffer: [*[u8]; 32] = undefined;
3177
    let path = try flattenPath(self, pathNode, &mut buffer[..]);
3178
3179
    return try resolvePath(self, node, access, path, startScope);
3180
}
3181
3182
/// Resolve a path (eg. ["lang", "resolver", "MAX_ERRORS"]) to a symbol,
3183
/// starting from the given scope.
3184
fn resolvePath(
3185
    self: *mut Resolver,
3186
    node: *ast::Node,
3187
    access: ast::Access,
3188
    path: *[*[u8]],
3189
    scope: *Scope
3190
) -> *mut Symbol throws (ResolveError) {
3191
    assert path.len <> 0, "resolvePath: empty path";
3192
    // Start by finding the root of the path.
3193
    let root = path[0];
3194
    let sym = findInScopeRecursive(scope, root, isAnySymbol)
3195
        else throw emitError(self, node, ErrorKind::UnresolvedSymbol(root));
3196
    let suffix = &path[1..];
3197
3198
    // Check visibility for symbol.
3199
    if not isSymbolVisible(sym, scope, self.scope) {
3200
        throw emitError(self, node, ErrorKind::UnresolvedSymbol(root));
3201
    }
3202
    // End condition.
3203
    if suffix.len == 0 {
3204
        return sym;
3205
    }
3206
    // Otherwise, we need to enter the next scope with the path suffix.
3207
    match sym.data {
3208
        case SymbolData::Module { scope, .. } => {
3209
            return try resolvePath(self, node, access, suffix, scope);
3210
        }
3211
        case SymbolData::Type(ty) => {
3212
            // Lazily resolve union body if not yet done.
3213
            try ensureNominalResolved(self, ty, node);
3214
3215
            if let case NominalType::Union(unionType) = *ty {
3216
                // TODO: Recurse with variant so we consolidate everything.
3217
                if suffix.len > 1 {
3218
                    throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3219
                }
3220
                let variantName = suffix[0];
3221
                let variantSym = try resolveUnionVariantAccess(
3222
                    self, node, access, unionType, variantName
3223
                );
3224
                // TODO: This shouldn't be here.
3225
                setNodeType(self, node, Type::Nominal(ty));
3226
                return variantSym;
3227
            }
3228
        }
3229
        else => {} // Fallthrough.
3230
    }
3231
    throw emitError(self, node, ErrorKind::InvalidScopeAccess);
3232
}
3233
3234
/// Resolve a module path (e.g., `foo::bar::baz`) to a module entry and scope.
3235
/// This traverses the module hierarchy, checking visibility at each step.
3236
fn resolveModulePath(
3237
    self: *mut Resolver,
3238
    module: *ast::Node
3239
) -> ResolvedModule throws (ResolveError) {
3240
    let mut startScope = self.scope;
3241
    let mut pathNode = module;
3242
3243
    // Handle `super` access.
3244
    if let superAccess = try checkSuperAccess(self, module) {
3245
        set startScope = superAccess.scope;
3246
        set pathNode = superAccess.child;
3247
    }
3248
    let mut pathBuf: [*[u8]; 16] = undefined;
3249
    let path = try flattenPath(self, pathNode, &mut pathBuf[..]);
3250
    if path.len == 0 {
3251
        throw emitError(self, module, ErrorKind::UnresolvedSymbol(""));
3252
    }
3253
    let parentName = path[0];
3254
3255
    // First, check if this is a sub-module of the start scope.
3256
    if let sym = findSymbolInScope(startScope, parentName) {
3257
        return try resolveModulePathRecursive(self, module, &path[1..], sym);
3258
    }
3259
    // Not a sub-module, so look in the global scope for a package root.
3260
    let sym = findSymbolInScope(self.pkgScope, parentName)
3261
        else throw emitError(self, module, ErrorKind::UnresolvedSymbol(parentName));
3262
3263
    return try resolveModulePathRecursive(self, module, &path[1..], sym);
3264
}
3265
3266
/// Recursively resolve the remaining path segments by traversing child modules.
3267
fn resolveModulePathRecursive(
3268
    self: *mut Resolver,
3269
    node: *ast::Node,
3270
    path: *[*[u8]],
3271
    sym: *Symbol
3272
) -> ResolvedModule throws (ResolveError) {
3273
    let case SymbolData::Module { entry, scope } = sym.data
3274
        else throw emitError(self, node, ErrorKind::Internal);
3275
3276
    if path.len == 0 {
3277
        return ResolvedModule { entry, scope };
3278
    }
3279
    let childName = path[0];
3280
    let childSym = findSymbolInScope(scope, childName)
3281
        else throw emitError(self, node, ErrorKind::UnresolvedSymbol(childName));
3282
3283
    if not isSymbolVisible(childSym, scope, self.scope) {
3284
        throw emitError(self, node, ErrorKind::UnresolvedSymbol(childName));
3285
    }
3286
    return try resolveModulePathRecursive(
3287
        self,
3288
        node,
3289
        &path[1..],
3290
        childSym
3291
    );
3292
}
3293
3294
/// Return whether a declaration requires generic arguments.
3295
fn isGenericDeclaration(node: *ast::Node) -> bool {
3296
    match node.value {
3297
        case ast::NodeValue::RecordDecl(decl) => return decl.params.len > 0,
3298
        case ast::NodeValue::UnionDecl(decl) => return decl.params.len > 0,
3299
        case ast::NodeValue::FnDecl(decl) => return decl.params.len > 0,
3300
        else => return false,
3301
    }
3302
}
3303
3304
/// Stack node used to stop cycles while walking ordinary nominal containers.
3305
record GenericRootVisit {
3306
    /// Nominal type visited at this stack entry.
3307
    nominal: *NominalType,
3308
    /// Previous stack entry.
3309
    parent: ?*GenericRootVisit,
3310
}
3311
3312
/// Return whether a nominal type is present in the visit stack.
3313
fn genericRootVisited(visit: ?*GenericRootVisit, nominal: *NominalType) -> bool {
3314
    let mut cursor = visit;
3315
    while let entry = cursor {
3316
        if entry.nominal == nominal {
3317
            return true;
3318
        }
3319
        set cursor = entry.parent;
3320
    }
3321
    return false;
3322
}
3323
3324
/// Mark generic specializations reached through one concrete type.
3325
fn markGenericDataTypeRootedInner(
3326
    self: *mut Resolver,
3327
    ty: Type,
3328
    visited: ?*GenericRootVisit,
3329
) -> bool {
3330
    match ty {
3331
        case Type::Pointer(pointer) =>
3332
            return markGenericDataTypeRootedInner(self, *pointer.target, visited),
3333
        case Type::Slice(slice) =>
3334
            return markGenericDataTypeRootedInner(self, *slice.item, visited),
3335
        case Type::Array(array) =>
3336
            return markGenericDataTypeRootedInner(self, *array.item, visited),
3337
        case Type::Optional(inner) =>
3338
            return markGenericDataTypeRootedInner(self, *inner, visited),
3339
        case Type::Fn(info) => {
3340
            let mut changed = markGenericDataTypeRootedInner(
3341
                self, *info.returnType, visited
3342
            );
3343
            for param in info.paramTypes {
3344
                set changed = markGenericDataTypeRootedInner(
3345
                    self, *param, visited
3346
                ) or changed;
3347
            }
3348
            for thrown in info.throwList {
3349
                set changed = markGenericDataTypeRootedInner(
3350
                    self, *thrown, visited
3351
                ) or changed;
3352
            }
3353
            return changed;
3354
        }
3355
        case Type::Nominal(nominal) => {
3356
            let mut cursor = self.genericDataSpecializations;
3357
            while let node = cursor {
3358
                let specialization = &node.specialization;
3359
                if specialization.nominal == nominal {
3360
                    if not *specialization.rooted {
3361
                        set *specialization.rooted = true;
3362
                        return true;
3363
                    }
3364
                    return false;
3365
                }
3366
                set cursor = node.next;
3367
            }
3368
            if genericRootVisited(visited, nominal) {
3369
                return false;
3370
            }
3371
            let visit = GenericRootVisit { nominal, parent: visited };
3372
            let mut changed = false;
3373
            match *nominal {
3374
                case NominalType::Record(recordType) => {
3375
                    for field in recordType.fields {
3376
                        set changed = markGenericDataTypeRootedInner(
3377
                            self, field.fieldType, &visit
3378
                        ) or changed;
3379
                    }
3380
                }
3381
                case NominalType::Union(unionType) => {
3382
                    for variant in unionType.variants {
3383
                        set changed = markGenericDataTypeRootedInner(
3384
                            self, variant.valueType, &visit
3385
                        ) or changed;
3386
                    }
3387
                }
3388
                case NominalType::Placeholder(_) => {}
3389
            }
3390
            return changed;
3391
        }
3392
        else => return false,
3393
    }
3394
}
3395
3396
/// Mark generic data specializations reachable from a concrete type.
3397
fn markGenericDataTypeRooted(self: *mut Resolver, ty: Type) -> bool {
3398
    return markGenericDataTypeRootedInner(self, ty, nil);
3399
}
3400
3401
/// Propagate explicit roots through arguments and specialized data members.
3402
fn validateGenericDataRoots(self: *mut Resolver) throws (ResolveError) {
3403
    loop {
3404
        let mut changed = false;
3405
        let mut cursor = self.genericDataSpecializations;
3406
        while let node = cursor {
3407
            let specialization = &node.specialization;
3408
            if *specialization.rooted {
3409
                for arg in specialization.args {
3410
                    set changed = markGenericDataTypeRooted(self, *arg) or changed;
3411
                }
3412
                match *specialization.nominal {
3413
                    case NominalType::Record(recordType) => {
3414
                        for field in recordType.fields {
3415
                            set changed = markGenericDataTypeRooted(
3416
                                self, field.fieldType
3417
                            ) or changed;
3418
                        }
3419
                    }
3420
                    case NominalType::Union(unionType) => {
3421
                        for variant in unionType.variants {
3422
                            set changed = markGenericDataTypeRooted(
3423
                                self, variant.valueType
3424
                            ) or changed;
3425
                        }
3426
                    }
3427
                    case NominalType::Placeholder(_) => {}
3428
                }
3429
            }
3430
            set cursor = node.next;
3431
        }
3432
        if not changed {
3433
            break;
3434
        }
3435
    }
3436
    let mut cursor = self.genericDataSpecializations;
3437
    while let node = cursor {
3438
        let specialization = &node.specialization;
3439
        if not *specialization.rooted {
3440
            throw emitError(
3441
                self, specialization.site, ErrorKind::GenericInstantiationRequired
3442
            );
3443
        }
3444
        set cursor = node.next;
3445
    }
3446
}
3447
3448
/// Look up a cached specialization by template and ordered arguments.
3449
export fn findGenericDataSpecialization(
3450
    self: *Resolver,
3451
    template: *Symbol,
3452
    args: *[*Type],
3453
) -> ?*GenericDataSpecialization {
3454
    let mut cursor = self.genericDataSpecializations;
3455
    while let node = cursor {
3456
        let entry = &node.specialization;
3457
        if entry.template == template and entry.args.len == args.len {
3458
            let mut equal = true;
3459
            for arg, i in args {
3460
                if not typesEqual(*entry.args[i], *arg) {
3461
                    set equal = false;
3462
                    break;
3463
                }
3464
            }
3465
            if equal {
3466
                return entry;
3467
            }
3468
        }
3469
        set cursor = node.next;
3470
    }
3471
    return nil;
3472
}
3473
3474
/// Look up a generic data specialization by its concrete nominal identity.
3475
export fn genericDataSpecializationForNominal(
3476
    self: *Resolver,
3477
    nominal: *NominalType,
3478
) -> ?*GenericDataSpecialization {
3479
    let mut cursor = self.genericDataSpecializations;
3480
    while let node = cursor {
3481
        if node.specialization.nominal == nominal {
3482
            return &node.specialization;
3483
        }
3484
        set cursor = node.next;
3485
    }
3486
    return nil;
3487
}
3488
3489
/// Find the declaration symbol that owns an ordinary nominal type.
3490
export fn symbolForNominal(
3491
    self: *Resolver,
3492
    nominal: *NominalType,
3493
) -> ?*Symbol {
3494
    for data in self.nodeData.entries {
3495
        if let sym = data.sym {
3496
            if let case SymbolData::Type(candidate) = sym.data; candidate == nominal {
3497
                return sym;
3498
            }
3499
        }
3500
    }
3501
    return nil;
3502
}
3503
3504
/// Resolve generic metadata lazily so applications are source-order independent.
3505
fn ensureGenericDataTemplate(self: *mut Resolver, sym: *mut Symbol)
3506
    throws (ResolveError)
3507
{
3508
    if genericTemplateFor(self, sym) <> nil {
3509
        return;
3510
    }
3511
    let prevScope = self.scope;
3512
    let prevMod = self.currentMod;
3513
    if let mid = moduleIdForSymbol(self, sym) {
3514
        if let moduleScope = self.moduleScopes[mid as u32] {
3515
            set self.scope = moduleScope;
3516
            set self.currentMod = mid;
3517
        }
3518
    }
3519
    match sym.node.value {
3520
        case ast::NodeValue::RecordDecl(decl) => {
3521
            try resolveGenericDataTemplate(
3522
                self, sym.node, decl.params, decl.fields, decl.derives, true
3523
            ) catch e {
3524
                set self.scope = prevScope;
3525
                set self.currentMod = prevMod;
3526
                throw e;
3527
            };
3528
        }
3529
        case ast::NodeValue::UnionDecl(decl) => {
3530
            try resolveGenericDataTemplate(
3531
                self, sym.node, decl.params, decl.variants, decl.derives, false
3532
            ) catch e {
3533
                set self.scope = prevScope;
3534
                set self.currentMod = prevMod;
3535
                throw e;
3536
            };
3537
        }
3538
        else => {
3539
            set self.scope = prevScope;
3540
            set self.currentMod = prevMod;
3541
            throw emitError(self, sym.node, ErrorKind::GenericDataExpected);
3542
        }
3543
    }
3544
    set self.scope = prevScope;
3545
    set self.currentMod = prevMod;
3546
}
3547
3548
/// Look up a possible inferred generic call target without emitting diagnostics.
3549
fn findGenericCandidateSymbol(
3550
    self: *Resolver,
3551
    node: *ast::Node,
3552
) -> ?*mut Symbol {
3553
    if let sym = symbolFor(self, node) {
3554
        return sym;
3555
    }
3556
    match node.value {
3557
        case ast::NodeValue::Ident(name) =>
3558
            return findAnySymbol(self.scope, name),
3559
        case ast::NodeValue::ScopeAccess(access) => {
3560
            let case ast::NodeValue::Ident(childName) = access.child.value
3561
                else return nil;
3562
            if let case ast::NodeValue::Super = access.parent.value {
3563
                let current = module::get(self.moduleGraph, self.currentMod) else return nil;
3564
                let parentId = current.parent else return nil;
3565
                let parentScope = self.moduleScopes[parentId as u32] else return nil;
3566
                return findSymbolInScope(parentScope, childName);
3567
            }
3568
            let sym = findGenericCandidateSymbol(self, access.parent) else return nil;
3569
            let case SymbolData::Module { scope, .. } = sym.data else return nil;
3570
            return findSymbolInScope(scope, childName);
3571
        }
3572
        else => return nil,
3573
    }
3574
}
3575
3576
/// Resolve a generic application's declaration symbol without requiring arguments.
3577
fn resolveGenericTarget(
3578
    self: *mut Resolver,
3579
    node: *ast::Node,
3580
) -> *mut Symbol throws (ResolveError) {
3581
    if let existing = symbolFor(self, node) {
3582
        return existing;
3583
    }
3584
    let mut sym: *mut Symbol = undefined;
3585
    match node.value {
3586
        case ast::NodeValue::Ident(name) => {
3587
            let found = findAnySymbol(self.scope, name) else {
3588
                throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
3589
            };
3590
            set sym = found;
3591
        }
3592
        case ast::NodeValue::ScopeAccess(access) => {
3593
            set sym = try resolveAccess(self, node, access, self.scope);
3594
        }
3595
        else => throw emitError(self, node, ErrorKind::GenericUnsupported),
3596
    }
3597
    if not isGenericDeclaration(sym.node) {
3598
        throw emitError(self, node, ErrorKind::GenericUnsupported);
3599
    }
3600
    setNodeSymbol(self, node, sym);
3601
    return sym;
3602
}
3603
3604
/// Resolve a generic record or union target.
3605
fn resolveGenericDataTarget(
3606
    self: *mut Resolver,
3607
    node: *ast::Node,
3608
) -> *mut Symbol throws (ResolveError) {
3609
    let sym = try resolveGenericTarget(self, node);
3610
    let case SymbolData::Type(_) = sym.data
3611
        else throw emitError(self, node, ErrorKind::GenericDataExpected);
3612
    match sym.node.value {
3613
        case ast::NodeValue::RecordDecl(_), ast::NodeValue::UnionDecl(_) => {}
3614
        else => throw emitError(self, node, ErrorKind::GenericDataExpected),
3615
    }
3616
    return sym;
3617
}
3618
3619
/// Build a concrete record specialization from substituted member types.
3620
fn specializeGenericRecord(
3621
    self: *mut Resolver,
3622
    template: *GenericTemplate,
3623
    decl: ast::RecordDecl,
3624
    sub: *Substitution,
3625
) -> RecordType throws (ResolveError) {
3626
    let a = alloc::arenaAllocator(&mut self.arena);
3627
    let mut fields: *mut [RecordField] = &mut [];
3628
    let mut offset: u32 = 0;
3629
    let mut alignment: u32 = 1;
3630
    for member, i in decl.fields {
3631
        let case ast::NodeValue::RecordField { field, type, .. } = member.value
3632
            else throw emitError(self, member, ErrorKind::Internal);
3633
        let concrete = try substituteType(self, *template.members[i], sub, type);
3634
        if hasUnresolvedNominalLayout(concrete) {
3635
            throw emitError(self, type, ErrorKind::GenericRecursiveLayout);
3636
        }
3637
        try ensureStorableType(self, type, concrete);
3638
        try ensureTypeResolved(self, concrete, type);
3639
        let layout = getTypeLayout(concrete);
3640
        set offset = mem::alignUp(offset, layout.alignment);
3641
        let mut name: ?*[u8] = nil;
3642
        if decl.labeled {
3643
            let nameNode = field else throw emitError(self, member, ErrorKind::Internal);
3644
            set name = try nodeName(self, nameNode);
3645
        }
3646
        fields.append(RecordField {
3647
            name,
3648
            fieldType: concrete,
3649
            offset: offset as i32,
3650
        }, a);
3651
        set offset += layout.size;
3652
        set alignment = max(alignment, layout.alignment);
3653
    }
3654
    return RecordType {
3655
        fields: &fields[..],
3656
        labeled: decl.labeled,
3657
        layout: Layout {
3658
            size: mem::alignUp(offset, alignment),
3659
            alignment,
3660
        },
3661
        declaredLinear: template.declaredLinear,
3662
    };
3663
}
3664
3665
/// Build a concrete union specialization from substituted variant types.
3666
fn specializeGenericUnion(
3667
    self: *mut Resolver,
3668
    templateSym: *mut Symbol,
3669
    template: *GenericTemplate,
3670
    decl: ast::UnionDecl,
3671
    sub: *Substitution,
3672
) -> UnionType throws (ResolveError) {
3673
    let a = alloc::arenaAllocator(&mut self.arena);
3674
    let mut variants: *mut [UnionVariant] = &mut [];
3675
    let mut iota: u32 = 0;
3676
    for variantNode, i in decl.variants {
3677
        let case ast::NodeValue::UnionDeclVariant(variantDecl) = variantNode.value
3678
            else throw emitError(self, variantNode, ErrorKind::Internal);
3679
        let valueType = try substituteType(
3680
            self, *template.members[i], sub, variantNode
3681
        );
3682
        if hasUnresolvedNominalLayout(valueType) {
3683
            throw emitError(self, variantNode, ErrorKind::GenericRecursiveLayout);
3684
        }
3685
        if let typeNode = variantDecl.type {
3686
            try ensureStorableType(self, typeNode, valueType);
3687
            try ensureTypeResolved(self, valueType, typeNode);
3688
        }
3689
        let name = try nodeName(self, variantDecl.name);
3690
        let tag = try variantTag(self, variantDecl, &mut iota, sub);
3691
        let symbol = allocSymbol(
3692
            self,
3693
            SymbolData::Variant {
3694
                type: valueType,
3695
                decl: template.decl,
3696
                ordinal: i,
3697
                index: tag,
3698
            },
3699
            name,
3700
            variantNode,
3701
            0,
3702
        );
3703
        set symbol.moduleId = templateSym.moduleId;
3704
        variants.append(UnionVariant { name, valueType, symbol }, a);
3705
    }
3706
    let info = computeUnionLayout(&variants[..]);
3707
    return UnionType {
3708
        variants: &variants[..],
3709
        layout: info.layout,
3710
        valOffset: info.valOffset,
3711
        isAllVoid: info.isAllVoid,
3712
        declaredLinear: template.declaredLinear,
3713
    };
3714
}
3715
3716
/// Return one canonical concrete specialization for a generic data application.
3717
fn specializeGenericData(
3718
    self: *mut Resolver,
3719
    site: *ast::Node,
3720
    templateSym: *mut Symbol,
3721
    args: *[*Type],
3722
    rooted: bool,
3723
) -> *mut NominalType throws (ResolveError) {
3724
    if let existing = findGenericDataSpecialization(self, templateSym, args) {
3725
        if rooted {
3726
            set *existing.rooted = true;
3727
        }
3728
        return existing.nominal;
3729
    }
3730
    if self.genericSpecializationCount >= MAX_GENERIC_SPECIALIZATIONS {
3731
        throw emitError(self, site, ErrorKind::GenericSpecializationLimit);
3732
    }
3733
    set self.genericSpecializationCount += 1;
3734
    let template = genericTemplateFor(self, templateSym)
3735
        else throw emitError(self, site, ErrorKind::Internal);
3736
    let a = alloc::arenaAllocator(&mut self.arena);
3737
    let mut storedArgs: *mut [*Type] = &mut [];
3738
    let rootedFlag = try! alloc::alloc(
3739
        &mut self.arena, @sizeOf(bool), @alignOf(bool)
3740
    ) as *mut bool;
3741
    set *rootedFlag = rooted;
3742
    for arg in args {
3743
        storedArgs.append(arg, a);
3744
    }
3745
    let nominal = allocNominalType(self, NominalType::Placeholder(template.decl));
3746
    let cacheNode = try! alloc::alloc(
3747
        &mut self.arena,
3748
        @sizeOf(GenericDataSpecializationNode),
3749
        @alignOf(GenericDataSpecializationNode),
3750
    ) as *mut GenericDataSpecializationNode;
3751
    set *cacheNode = GenericDataSpecializationNode {
3752
        specialization: GenericDataSpecialization {
3753
            template: templateSym,
3754
            args: &storedArgs[..],
3755
            nominal,
3756
            rooted: rootedFlag,
3757
            site,
3758
        },
3759
        next: self.genericDataSpecializations,
3760
    };
3761
    set self.genericDataSpecializations = cacheNode;
3762
    let sub = Substitution { params: template.params, args: &storedArgs[..] };
3763
    match template.decl.value {
3764
        case ast::NodeValue::RecordDecl(decl) => {
3765
            let recordType = try specializeGenericRecord(self, template, decl, &sub);
3766
            set *nominal = NominalType::Record(recordType);
3767
        }
3768
        case ast::NodeValue::UnionDecl(decl) => {
3769
            let unionType = try specializeGenericUnion(
3770
                self, templateSym, template, decl, &sub
3771
            );
3772
            set *nominal = NominalType::Union(unionType);
3773
        }
3774
        else => throw emitError(self, site, ErrorKind::GenericDataExpected),
3775
    }
3776
    return nominal;
3777
}
3778
3779
/// Resolve one generic argument according to its declaration kind.
3780
fn resolveGenericArgument(
3781
    self: *mut Resolver,
3782
    argNode: *ast::Node,
3783
    param: *GenericParamType,
3784
) -> Type throws (ResolveError) {
3785
    if let constType = param.constType {
3786
        let mut expr = argNode;
3787
        if let case ast::NodeValue::TypeSig(ast::TypeSig::Nominal(name)) = argNode.value {
3788
            set expr = name;
3789
        }
3790
        let actual = try visit(self, expr, *constType);
3791
        if let value = constValueEntry(self, expr) {
3792
            let case ConstValue::Int(int) = value
3793
                else throw emitError(self, expr, ErrorKind::ConstExprRequired);
3794
            if not validateConstIntRange(value, *constType) {
3795
                throw emitError(self, expr, ErrorKind::NumericLiteralOverflow);
3796
            }
3797
            let _ = try expectAssignable(self, *constType, actual, expr);
3798
            let case ConstValue::Int(canonical) = castConstInt(int, *constType)
3799
                else throw emitError(self, expr, ErrorKind::Internal);
3800
            return Type::ConstArgument { type: constType, value: canonical };
3801
        }
3802
        let _ = try expectAssignable(self, *constType, actual, expr);
3803
        if isConstExpr(self, expr) and containsGenericConstExpr(self, expr) {
3804
            return Type::GenericConstExpr { type: constType, expr };
3805
        }
3806
        throw emitError(self, expr, ErrorKind::ConstExprRequired);
3807
    }
3808
    if let case ast::NodeValue::TypeSig(_) = argNode.value {
3809
        let arg = try resolveGenericValueType(self, argNode);
3810
        return try materializeConcreteGenericData(self, arg, argNode);
3811
    }
3812
    throw emitError(self, argNode, ErrorKind::GenericUnsupported);
3813
}
3814
3815
/// Resolve and canonicalize one generic data type application.
3816
fn resolveGenericDataApply(
3817
    self: *mut Resolver,
3818
    node: *ast::Node,
3819
    app: ast::GenericApply,
3820
    rooted: bool,
3821
) -> *mut NominalType throws (ResolveError) {
3822
    let templateSym = try resolveGenericDataTarget(self, app.target);
3823
    try ensureGenericDataTemplate(self, templateSym);
3824
    let template = genericTemplateFor(self, templateSym)
3825
        else throw emitError(self, node, ErrorKind::Internal);
3826
    if app.args.len <> template.params.len {
3827
        throw emitError(self, node, ErrorKind::GenericArgumentCount(CountMismatch {
3828
            expected: template.params.len,
3829
            actual: app.args.len,
3830
        }));
3831
    }
3832
    let a = alloc::arenaAllocator(&mut self.arena);
3833
    let mut args: *mut [*Type] = &mut [];
3834
    for argNode, i in app.args {
3835
        let argType = try resolveGenericArgument(self, argNode, template.params[i]);
3836
        if containsGenericParameter(argType) {
3837
            throw emitError(self, argNode, ErrorKind::GenericConcreteArgumentsRequired);
3838
        }
3839
        args.append(allocType(self, argType), a);
3840
    }
3841
    let nominal = try specializeGenericData(
3842
        self, node, templateSym, &args[..], rooted
3843
    );
3844
3845
    setNodeSymbol(self, node, templateSym);
3846
    setNodeType(self, node, Type::Nominal(nominal));
3847
    return nominal;
3848
}
3849
3850
/// Return the function specialization list for lowering.
3851
export fn genericFnSpecializations(
3852
    self: *Resolver,
3853
) -> ?*GenericFnSpecializationNode {
3854
    return self.genericFnSpecializations;
3855
}
3856
3857
/// Look up a canonical function specialization.
3858
export fn findGenericFnSpecialization(
3859
    self: *Resolver,
3860
    template: *Symbol,
3861
    args: *[*Type],
3862
) -> ?*GenericFnSpecialization {
3863
    let mut cursor = self.genericFnSpecializations;
3864
    while let node = cursor {
3865
        let entry = &node.specialization;
3866
        if entry.template == template and entry.args.len == args.len {
3867
            let mut equal = true;
3868
            for arg, i in args {
3869
                if not typesEqual(*entry.args[i], *arg) {
3870
                    set equal = false;
3871
                    break;
3872
                }
3873
            }
3874
            if equal {
3875
                return entry;
3876
            }
3877
        }
3878
        set cursor = node.next;
3879
    }
3880
    return nil;
3881
}
3882
3883
/// Create or retrieve one concrete generic function specialization.
3884
fn internGenericFnSpecialization(
3885
    self: *mut Resolver,
3886
    templateSym: *mut Symbol,
3887
    args: *[*Type],
3888
    site: *ast::Node,
3889
    depth: u16,
3890
) -> *GenericFnSpecialization throws (ResolveError) {
3891
    if let existing = findGenericFnSpecialization(self, templateSym, args) {
3892
        return existing;
3893
    }
3894
    if self.genericSpecializationCount >= MAX_GENERIC_SPECIALIZATIONS {
3895
        throw emitError(self, site, ErrorKind::GenericSpecializationLimit);
3896
    }
3897
    set self.genericSpecializationCount += 1;
3898
    let template = genericTemplateFor(self, templateSym)
3899
        else throw emitError(self, site, ErrorKind::Internal);
3900
    let signature = template.signature
3901
        else throw emitError(self, site, ErrorKind::GenericFunctionExpected);
3902
    let a = alloc::arenaAllocator(&mut self.arena);
3903
    let mut storedArgs: *mut [*Type] = &mut [];
3904
    for arg in args {
3905
        storedArgs.append(allocType(self, *arg), a);
3906
    }
3907
    let sub = Substitution { params: template.params, args: &storedArgs[..] };
3908
    let concrete = try substituteType(self, Type::Fn(signature), &sub, site);
3909
    let case Type::Fn(fnType) = concrete
3910
        else throw emitError(self, site, ErrorKind::Internal);
3911
    let _ = markGenericDataTypeRooted(self, concrete);
3912
    let cacheNode = try! alloc::alloc(
3913
        &mut self.arena,
3914
        @sizeOf(GenericFnSpecializationNode),
3915
        @alignOf(GenericFnSpecializationNode),
3916
    ) as *mut GenericFnSpecializationNode;
3917
    set *cacheNode = GenericFnSpecializationNode {
3918
        specialization: GenericFnSpecialization {
3919
            template: templateSym,
3920
            args: &storedArgs[..],
3921
            fnType,
3922
            site,
3923
            state: GenericFnState::Queued,
3924
            depth,
3925
        },
3926
        next: self.genericFnSpecializations,
3927
    };
3928
    set self.genericFnSpecializations = cacheNode;
3929
    return &cacheNode.specialization;
3930
}
3931
3932
/// Retain a generic call edge for package-wide specialization closure.
3933
fn recordGenericFnDependency(
3934
    self: *mut Resolver,
3935
    node: *ast::Node,
3936
    caller: ?*mut Symbol,
3937
    callee: *mut Symbol,
3938
    args: *[*Type],
3939
    fnType: *FnType,
3940
) {
3941
    let a = alloc::arenaAllocator(&mut self.arena);
3942
    let mut storedArgs: *mut [*Type] = &mut [];
3943
    for arg in args {
3944
        storedArgs.append(allocType(self, *arg), a);
3945
    }
3946
    let dependency = try! alloc::alloc(
3947
        &mut self.arena,
3948
        @sizeOf(GenericFnDependency),
3949
        @alignOf(GenericFnDependency),
3950
    ) as *mut GenericFnDependency;
3951
    set *dependency = GenericFnDependency {
3952
        caller,
3953
        callee,
3954
        args: &storedArgs[..],
3955
        site: node,
3956
        next: self.genericFnDependencies,
3957
    };
3958
    set self.genericFnDependencies = dependency;
3959
    setNodeSymbol(self, node, callee);
3960
    setNodeType(self, node, Type::Fn(fnType));
3961
    set self.nodeData.entries[node.id].extra =
3962
        NodeExtra::GenericFnDependency(dependency);
3963
}
3964
3965
/// Resolve a generic function application as a root, concrete call, or symbolic edge.
3966
fn resolveGenericFnApply(
3967
    self: *mut Resolver,
3968
    node: *ast::Node,
3969
    app: ast::GenericApply,
3970
    rooted: bool,
3971
) -> *FnType throws (ResolveError) {
3972
    let templateSym = try resolveGenericTarget(self, app.target);
3973
    let case SymbolData::Value { type: Type::Fn(_), .. } = templateSym.data
3974
        else throw emitError(self, app.target, ErrorKind::GenericFunctionExpected);
3975
    let template = genericTemplateFor(self, templateSym)
3976
        else throw emitError(self, node, ErrorKind::Internal);
3977
    let signature = template.signature
3978
        else throw emitError(self, app.target, ErrorKind::GenericFunctionExpected);
3979
    if app.args.len <> template.params.len {
3980
        throw emitError(self, node, ErrorKind::GenericArgumentCount(CountMismatch {
3981
            expected: template.params.len,
3982
            actual: app.args.len,
3983
        }));
3984
    }
3985
    let a = alloc::arenaAllocator(&mut self.arena);
3986
    let mut args: *mut [*Type] = &mut [];
3987
    let caller = currentGenericTemplateSymbol(self);
3988
    for argNode, i in app.args {
3989
        let argType = try resolveGenericArgument(self, argNode, template.params[i]);
3990
        let symbolic = containsGenericParameter(argType);
3991
        if symbolic and caller == nil {
3992
            throw emitError(
3993
                self, argNode, ErrorKind::GenericConcreteArgumentsRequired
3994
            );
3995
        }
3996
        if not symbolic {
3997
            for bound in template.params[i].bounds {
3998
                if findInstance(self, bound, argType) == nil {
3999
                    throw emitError(
4000
                        self, argNode, ErrorKind::GenericBoundUnsatisfied(bound.name)
4001
                    );
4002
                }
4003
            }
4004
        }
4005
        args.append(allocType(self, argType), a);
4006
    }
4007
    let sub = Substitution { params: template.params, args: &args[..] };
4008
    let applied = try substituteType(self, Type::Fn(signature), &sub, node);
4009
    let case Type::Fn(appliedFn) = applied
4010
        else throw emitError(self, node, ErrorKind::Internal);
4011
    if rooted {
4012
        if caller <> nil {
4013
            throw emitError(self, node, ErrorKind::GenericConcreteArgumentsRequired);
4014
        }
4015
        let specialization = try internGenericFnSpecialization(
4016
            self, templateSym, &args[..], node, 0
4017
        );
4018
        setNodeSymbol(self, node, templateSym);
4019
        setNodeType(self, node, Type::Fn(specialization.fnType));
4020
        set self.nodeData.entries[node.id].extra =
4021
            NodeExtra::GenericFnCall(specialization);
4022
        return specialization.fnType;
4023
    }
4024
    if caller == nil {
4025
        if let existing = findGenericFnSpecialization(self, templateSym, &args[..]) {
4026
            setNodeSymbol(self, node, templateSym);
4027
            setNodeType(self, node, Type::Fn(existing.fnType));
4028
            set self.nodeData.entries[node.id].extra =
4029
                NodeExtra::GenericFnCall(existing);
4030
            return existing.fnType;
4031
        }
4032
    }
4033
    recordGenericFnDependency(
4034
        self, node, caller, templateSym, &args[..], appliedFn
4035
    );
4036
    return appliedFn;
4037
}
4038
4039
/// Expand explicit roots through symbolic generic calls to a fixed point.
4040
fn closeGenericFnSpecializations(self: *mut Resolver) throws (ResolveError) {
4041
    loop {
4042
        let mut queued: ?*mut GenericFnSpecialization = nil;
4043
        let mut cursor = self.genericFnSpecializations;
4044
        while let node = cursor {
4045
            if let case GenericFnState::Queued = node.specialization.state {
4046
                set queued = &mut node.specialization;
4047
                break;
4048
            }
4049
            set cursor = node.next;
4050
        }
4051
        let specialization = queued else break;
4052
        set specialization.state = GenericFnState::Lowering;
4053
        let callerTemplate = genericTemplateFor(self, specialization.template)
4054
            else throw emitError(self, specialization.site, ErrorKind::Internal);
4055
        let callerSub = Substitution {
4056
            params: callerTemplate.params,
4057
            args: specialization.args,
4058
        };
4059
        let mut edge = self.genericFnDependencies;
4060
        while let dependency = edge {
4061
            if dependency.caller == specialization.template {
4062
                let a = alloc::arenaAllocator(&mut self.arena);
4063
                let mut concreteArgs: *mut [*Type] = &mut [];
4064
                for arg in dependency.args {
4065
                    let concrete = try substituteType(
4066
                        self, *arg, &callerSub, dependency.site
4067
                    );
4068
                    if containsGenericParameter(concrete) {
4069
                        throw emitError(
4070
                            self,
4071
                            dependency.site,
4072
                            ErrorKind::GenericConcreteArgumentsRequired,
4073
                        );
4074
                    }
4075
                    concreteArgs.append(allocType(self, concrete), a);
4076
                }
4077
                let calleeTemplate = genericTemplateFor(self, dependency.callee)
4078
                    else throw emitError(
4079
                        self, dependency.site, ErrorKind::Internal
4080
                    );
4081
                for arg, i in concreteArgs {
4082
                    for bound in calleeTemplate.params[i].bounds {
4083
                        if findInstance(self, bound, *arg) == nil {
4084
                            throw emitError(
4085
                                self,
4086
                                dependency.site,
4087
                                ErrorKind::GenericBoundUnsatisfied(bound.name),
4088
                            );
4089
                        }
4090
                    }
4091
                }
4092
                let mut callee = findGenericFnSpecialization(
4093
                    self, dependency.callee, &concreteArgs[..]
4094
                );
4095
                if callee == nil {
4096
                    if specialization.depth >= MAX_GENERIC_SPECIALIZATION_DEPTH {
4097
                        throw emitError(
4098
                            self,
4099
                            dependency.site,
4100
                            ErrorKind::GenericSpecializationChain,
4101
                        );
4102
                    }
4103
                    set callee = try internGenericFnSpecialization(
4104
                        self,
4105
                        dependency.callee,
4106
                        &concreteArgs[..],
4107
                        dependency.site,
4108
                        specialization.depth + 1,
4109
                    );
4110
                }
4111
                let concreteCallee = callee
4112
                    else throw emitError(
4113
                        self, dependency.site, ErrorKind::Internal
4114
                    );
4115
                let resolution = try! alloc::alloc(
4116
                    &mut self.arena,
4117
                    @sizeOf(GenericFnDependencyResolution),
4118
                    @alignOf(GenericFnDependencyResolution),
4119
                ) as *mut GenericFnDependencyResolution;
4120
                set *resolution = GenericFnDependencyResolution {
4121
                    dependency,
4122
                    caller: specialization,
4123
                    callee: concreteCallee,
4124
                    next: self.genericFnDependencyResolutions,
4125
                };
4126
                set self.genericFnDependencyResolutions = resolution;
4127
            }
4128
            set edge = dependency.next;
4129
        }
4130
        set specialization.state = GenericFnState::Complete;
4131
    }
4132
4133
    // Non-generic calls may only select entries made reachable by the closure.
4134
    let mut edge = self.genericFnDependencies;
4135
    while let dependency = edge {
4136
        if dependency.caller == nil {
4137
            let specialization = findGenericFnSpecialization(
4138
                self, dependency.callee, dependency.args
4139
            ) else {
4140
                throw emitError(
4141
                    self,
4142
                    dependency.site,
4143
                    ErrorKind::GenericFunctionInstantiationRequired,
4144
                );
4145
            };
4146
            set self.nodeData.entries[dependency.site.id].extra =
4147
                NodeExtra::GenericFnCall(specialization);
4148
            set self.nodeData.entries[dependency.site.id].ty =
4149
                Type::Fn(specialization.fnType);
4150
        }
4151
        set edge = dependency.next;
4152
    }
4153
}
4154
4155
/// Select the concrete callee for a symbolic edge while lowering a specialization.
4156
export fn genericFnSpecializationForDependency(
4157
    self: *Resolver,
4158
    dependency: *GenericFnDependency,
4159
    caller: *GenericFnSpecialization,
4160
) -> ?*GenericFnSpecialization {
4161
    let mut resolution = self.genericFnDependencyResolutions;
4162
    while let entry = resolution {
4163
        if entry.dependency == dependency and entry.caller == caller {
4164
            return entry.callee;
4165
        }
4166
        set resolution = entry.next;
4167
    }
4168
    return nil;
4169
}
4170
4171
/// Resolve a type name, which could be an identifier or scoped path.
4172
fn resolveTypeName(self: *mut Resolver, node: *ast::Node) -> *NominalType throws (ResolveError) {
4173
    match node.value {
4174
        case ast::NodeValue::Ident(name) => {
4175
            let sym = findTypeSymbol(self.scope, name)
4176
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
4177
            let case SymbolData::Type(ty) = sym.data
4178
                else throw emitError(self, node, ErrorKind::Internal);
4179
            if isGenericDeclaration(sym.node) {
4180
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4181
            }
4182
4183
            setNodeSymbol(self, node, sym);
4184
4185
            return ty;
4186
        }
4187
        case ast::NodeValue::ScopeAccess(access) => {
4188
            let sym = try resolveAccess(self, node, access, self.scope);
4189
            let case SymbolData::Type(ty) = sym.data
4190
                else throw emitError(self, node, ErrorKind::Internal);
4191
            if isGenericDeclaration(sym.node) {
4192
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4193
            }
4194
4195
            setNodeSymbol(self, node, sym);
4196
4197
            return ty;
4198
        }
4199
        case ast::NodeValue::GenericApply(app) =>
4200
            return try resolveGenericDataApply(self, node, app, false),
4201
        else => panic "resolveTypeName: unsupported node value",
4202
    }
4203
}
4204
4205
/// Visit a top-level declaration in the declaration phase.
4206
/// This binds all names and analyzes signatures, types, and initializers.
4207
/// Function bodies are deferred to the definition phase.
4208
///
4209
/// Nb. User-defined types are already handled by this point.
4210
fn visitDecl(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
4211
    match node.value {
4212
        case ast::NodeValue::FnDecl(_),
4213
             ast::NodeValue::ConstDecl(_),
4214
             ast::NodeValue::Mod(_),
4215
             ast::NodeValue::Use(_) => {
4216
            // Handled in previous passes.
4217
        }
4218
        case ast::NodeValue::StaticDecl(_) => {
4219
            try infer(self, node);
4220
        }
4221
        case ast::NodeValue::InstanceDecl { traitName, targetType, methods } => {
4222
            try resolveInstanceDecl(self, node, traitName, targetType, methods);
4223
        }
4224
        case ast::NodeValue::MethodDecl { name, receiverName, receiverType, sig, body, attrs } => {
4225
            try resolveMethodDecl(self, node, name, receiverName, receiverType, sig, attrs);
4226
        }
4227
        case ast::NodeValue::Instantiate(applications) => {
4228
            for application in applications {
4229
                let case ast::NodeValue::GenericApply(app) = application.value
4230
                    else throw emitError(self, application, ErrorKind::GenericUnsupported);
4231
                if self.genericRoots >= MAX_GENERIC_ROOTS {
4232
                    throw emitError(self, application, ErrorKind::GenericRootLimit);
4233
                }
4234
                set self.genericRoots += 1;
4235
                let target = try resolveGenericTarget(self, app.target);
4236
                match target.data {
4237
                    case SymbolData::Type(_) => {
4238
                        let _ = try resolveGenericDataApply(self, application, app, true);
4239
                    }
4240
                    case SymbolData::Value { type: Type::Fn(_), .. } => {
4241
                        let _ = try resolveGenericFnApply(self, application, app, true);
4242
                    }
4243
                    else => {
4244
                        throw emitError(self, app.target, ErrorKind::GenericUnsupported);
4245
                    }
4246
                }
4247
            }
4248
            setNodeType(self, node, Type::Void);
4249
        }
4250
        else => {
4251
            // Ignore non-declaration nodes.
4252
        }
4253
    }
4254
}
4255
4256
/// Require the current declaration to be unsafe.
4257
fn requireUnsafe(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
4258
    if self.unsafeDepth == 0 {
4259
        throw emitError(self, node, ErrorKind::UnsafeOperation);
4260
    }
4261
}
4262
4263
/// Reject calls from safe code through unsafe function types.
4264
fn checkUnsafeCall(self: *mut Resolver, node: *ast::Node, info: *FnType)
4265
    throws (ResolveError)
4266
{
4267
    if info.isUnsafe and self.unsafeDepth == 0 {
4268
        throw emitError(self, node, ErrorKind::UnsafeCall);
4269
    }
4270
}
4271
4272
/// Visit a top-level definition, recursing into sub-modules.
4273
fn visitDef(self: *mut Resolver, node: *ast::Node) throws (ResolveError) {
4274
    match node.value {
4275
        case ast::NodeValue::FnDecl(decl) => {
4276
            try resolveFnDeclBody(self, node, decl) catch {
4277
                return;
4278
            };
4279
        }
4280
        case ast::NodeValue::Mod(decl) => {
4281
            if not shouldAnalyzeModule(self, decl.attrs) {
4282
                return;
4283
            }
4284
            let modName = try nodeName(self, decl.name);
4285
            let submod = try enterSubModule(self, modName, node);
4286
            let case ast::NodeValue::Block(block) = submod.root.value
4287
                else panic "visitDef: expected block for module root";
4288
            let mut isUnsafe = false;
4289
            if let attrs = decl.attrs {
4290
                set isUnsafe = ast::attributesContains(&attrs, ast::Attribute::Unsafe);
4291
            }
4292
            if isUnsafe {
4293
                set self.unsafeDepth += 1;
4294
            }
4295
            try resolveModuleDefs(self, &block) catch e {
4296
                if isUnsafe { set self.unsafeDepth -= 1; }
4297
                exitModuleScope(self, submod);
4298
                throw e;
4299
            };
4300
            if isUnsafe {
4301
                set self.unsafeDepth -= 1;
4302
            }
4303
            exitModuleScope(self, submod);
4304
        }
4305
        case ast::NodeValue::RecordDecl(_),
4306
             ast::NodeValue::UnionDecl(_),
4307
             ast::NodeValue::Use(_),
4308
             ast::NodeValue::TraitDecl { .. } => {
4309
            // Skip: already analyzed in declaration phase.
4310
        }
4311
        case ast::NodeValue::InstanceDecl { methods, .. } => {
4312
            try resolveInstanceMethodBodies(self, methods);
4313
        }
4314
        case ast::NodeValue::MethodDecl { receiverName, sig, body, .. } => {
4315
            try resolveMethodBody(self, node, receiverName, sig, body);
4316
        }
4317
        else => {
4318
            // FIXME: This allows module-level statements that should
4319
            // normally only be valid inside function bodies. We currently
4320
            // need this because of how tests are written, but it should
4321
            // be eventually removed.
4322
            try infer(self, node) catch {
4323
                return;
4324
            };
4325
        }
4326
    }
4327
}
4328
4329
/// Try to infer a node's type.
4330
fn infer(self: *mut Resolver, node: *ast::Node) -> Type throws (ResolveError) {
4331
    return try visit(self, node, Type::Unknown);
4332
}
4333
4334
/// Reject nested references while allowing a direct parameter reference.
4335
fn validateValueTypeReferences(self: *mut Resolver, node: *ast::Node, ty: Type)
4336
    throws (ResolveError)
4337
{
4338
    if isRefType(ty) {
4339
        if let case Type::Pointer(pointer) = ty {
4340
            if containsRef(*pointer.target) {
4341
                throw emitError(self, node, ErrorKind::InvalidRefPosition);
4342
            }
4343
        } else if let case Type::Slice(slice) = ty {
4344
            if containsRef(*slice.item) {
4345
                throw emitError(self, node, ErrorKind::InvalidRefPosition);
4346
            }
4347
        }
4348
    } else if containsRef(ty) {
4349
        throw emitError(self, node, ErrorKind::InvalidRefPosition);
4350
    }
4351
}
4352
4353
/// Require a type that may be stored or escape a call.
4354
fn ensureStorableType(self: *mut Resolver, node: *ast::Node, ty: Type)
4355
    throws (ResolveError)
4356
{
4357
    if containsRef(ty) {
4358
        throw emitError(self, node, ErrorKind::InvalidRefPosition);
4359
    }
4360
}
4361
4362
/// Resolve a type signature node.
4363
fn resolveValueType(self: *mut Resolver, node: *ast::Node) -> Type throws (ResolveError) {
4364
    let ty = try visit(self, node, Type::Unknown);
4365
    // Opaque value types are not allowed.
4366
    if ty == Type::Opaque {
4367
        throw emitError(self, node, ErrorKind::OpaqueTypeNotAllowed);
4368
    }
4369
    try validateValueTypeReferences(self, node, ty);
4370
    return ty;
4371
}
4372
4373
/// Analyze a node's type and check that it can be assigned to the expected type.
4374
fn checkAssignable(self: *mut Resolver, node: *ast::Node, expected: Type) -> Type throws (ResolveError) {
4375
    let actual = try visit(self, node, expected);
4376
    let _ = try expectAssignable(self, expected, actual, node);
4377
    return actual;
4378
}
4379
4380
/// Analyze a node and propagate the resolved type.
4381
/// The `hint` parameter provides type context for inference and validation.
4382
/// When `nil`, the type must be inferred from the expression itself.
4383
fn visit(self: *mut Resolver, node: *ast::Node, hint: Type) -> Type
4384
    throws (ResolveError)
4385
{
4386
    if let ty = typeFor(self, node) {
4387
        return ty;
4388
    }
4389
    match node.value {
4390
        case ast::NodeValue::Ident(name) => {
4391
            let sym = findAnySymbol(self.scope, name)
4392
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
4393
            setNodeSymbol(self, node, sym);
4394
            match sym.data {
4395
                case SymbolData::Value { type, .. } => {
4396
                    if isGenericDeclaration(sym.node) {
4397
                        throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4398
                    }
4399
                    return setNodeType(self, node, type);
4400
                }
4401
                case SymbolData::Constant { type, value } => {
4402
                    if let val = value {
4403
                        setNodeConstValue(self, node, val);
4404
                    }
4405
                    return setNodeType(self, node, type);
4406
                },
4407
                case SymbolData::Type(t) => {
4408
                    if isGenericDeclaration(sym.node) {
4409
                        throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
4410
                    }
4411
                    return setNodeType(self, node, Type::Nominal(t));
4412
                }
4413
                case SymbolData::TypeParameter(param) => {
4414
                    set *param.used = true;
4415
                    return setNodeType(self, node, Type::Parameter(param));
4416
                }
4417
                case SymbolData::ConstParameter(param) => {
4418
                    set *param.used = true;
4419
                    let ty = param.constType else {
4420
                        throw emitError(self, node, ErrorKind::Internal);
4421
                    };
4422
                    return setNodeType(self, node, *ty);
4423
                }
4424
                case SymbolData::Variant { .. } =>
4425
                    return Type::Void,
4426
                case SymbolData::Module { .. } =>
4427
                    throw emitError(self, node, ErrorKind::UnexpectedModuleName),
4428
                case SymbolData::Trait(_) =>
4429
                    throw emitError(self, node, ErrorKind::UnexpectedTraitName),
4430
            }
4431
        },
4432
        case ast::NodeValue::Call(call) =>
4433
            return try resolveCall(self, node, call, CallCtx::Normal, hint),
4434
        case ast::NodeValue::FieldAccess(access) => return try resolveFieldAccess(self, node, access),
4435
        case ast::NodeValue::BinOp(binop) => return try resolveBinOp(self, node, binop),
4436
        case ast::NodeValue::Block(block) => return try resolveBlock(self, node, block),
4437
        case ast::NodeValue::FnDecl(decl) => {
4438
            if decl.params.len > 0 {
4439
                throw emitError(self, node, ErrorKind::GenericFnNested);
4440
            }
4441
            throw emitError(self, node, ErrorKind::UnexpectedNode(node));
4442
        }
4443
        case ast::NodeValue::Let(decl) => return try resolveLet(self, node, decl),
4444
        case ast::NodeValue::ConstDecl(decl) => return try resolveConstOrStatic(
4445
            self, node, decl.ident, decl.type, decl.value, decl.attrs, true
4446
        ),
4447
        case ast::NodeValue::StaticDecl(decl) => return try resolveConstOrStatic(
4448
            self, node, decl.ident, decl.type, decl.value, decl.attrs, false
4449
        ),
4450
        case ast::NodeValue::FnParam(param) => return try resolveFnParam(self, node, param),
4451
        case ast::NodeValue::If(cond) => return try resolveIf(self, node, cond),
4452
        case ast::NodeValue::CondExpr(cond) => return try resolveCondExpr(self, node, cond),
4453
        case ast::NodeValue::IfLet(cond) => return try resolveIfLet(self, node, cond),
4454
        case ast::NodeValue::While(loopNode) => return try resolveWhile(self, node, loopNode),
4455
        case ast::NodeValue::WhileLet(loopNode) => return try resolveWhileLet(self, node, loopNode),
4456
        case ast::NodeValue::For(loopNode) => return try resolveFor(self, node, loopNode),
4457
        case ast::NodeValue::Loop { body } => {
4458
            let loopType = try visitLoop(self, body);
4459
            return setNodeType(self, node, loopType);
4460
        },
4461
        case ast::NodeValue::Break => {
4462
            try ensureInsideLoop(self, node);
4463
            // Mark that the current loop has a reachable break.
4464
            set self.loopStack[self.loopDepth - 1].hasBreak = true;
4465
4466
            return setNodeType(self, node, Type::Never);
4467
        },
4468
        case ast::NodeValue::Continue => {
4469
            try ensureInsideLoop(self, node);
4470
            return setNodeType(self, node, Type::Never);
4471
        },
4472
        case ast::NodeValue::Match(sw) => return try resolveMatch(self, node, sw),
4473
        case ast::NodeValue::MatchProng(_) => panic "visit: `MatchProng` not handled here",
4474
        case ast::NodeValue::LetElse(letElse) => return try resolveLetElse(self, node, letElse),
4475
        case ast::NodeValue::BuiltinCall { kind, args } => return try resolveBuiltinCall(self, node, kind, args),
4476
        case ast::NodeValue::Assign(assign) => return try resolveAssign(self, node, assign),
4477
        case ast::NodeValue::RecordLit(lit) => return try resolveRecordLit(self, node, lit, hint),
4478
        case ast::NodeValue::ArrayLit(items) => return try resolveArrayLit(self, node, items, hint),
4479
        case ast::NodeValue::ArrayRepeatLit(lit) => return try resolveArrayRepeat(self, node, lit, hint),
4480
        case ast::NodeValue::Subscript { container, index } => return try resolveSubscript(self, node, container, index),
4481
        case ast::NodeValue::GenericApply(app) => {
4482
            let fnType = try resolveGenericFnApply(self, node, app, false);
4483
            return setNodeType(self, node, Type::Fn(fnType));
4484
        }
4485
        case ast::NodeValue::Instantiate(_) =>
4486
            throw emitError(self, node, ErrorKind::GenericUnsupported),
4487
        case ast::NodeValue::ScopeAccess(access) => return try resolveScopeAccess(self, node, access),
4488
        case ast::NodeValue::AddressOf(addr) => return try resolveAddressOf(self, node, addr, hint),
4489
        case ast::NodeValue::Deref(target) => return try resolveDeref(self, node, target, hint),
4490
        case ast::NodeValue::As(expr) => return try resolveAs(self, node, expr),
4491
        case ast::NodeValue::Range(range) => return try resolveRange(self, node, range),
4492
        case ast::NodeValue::Try(expr) => return try resolveTry(self, node, expr, hint),
4493
        case ast::NodeValue::Return { value } => return try resolveReturn(self, node, value),
4494
        case ast::NodeValue::Throw { expr } => return try resolveThrow(self, node, expr),
4495
        case ast::NodeValue::Panic { message } => {
4496
            // TODO: Have easy access to string type.
4497
            try visitOptional(self, message, Type::Slice(SliceType {
4498
                class: types::PointerClass::Owned,
4499
                item: allocType(self, Type::U8),
4500
                mutable: false,
4501
            }));
4502
            return setNodeType(self, node, Type::Never);
4503
        },
4504
        case ast::NodeValue::Assert { condition, message } => {
4505
            try visit(self, condition, Type::Bool);
4506
            // TODO: Have easy access to string type.
4507
            try visitOptional(self, message, Type::Slice(SliceType {
4508
                class: types::PointerClass::Owned,
4509
                item: allocType(self, Type::U8),
4510
                mutable: false,
4511
            }));
4512
            return setNodeType(self, node, Type::Void);
4513
        },
4514
        case ast::NodeValue::UnOp(unop) => return try resolveUnOp(self, node, unop),
4515
        case ast::NodeValue::ExprStmt(expr) => {
4516
            // Pass `Void` as expected type to indicate value is discarded.
4517
            let exprTy = try visit(self, expr, Type::Void);
4518
            return setNodeType(self, node, unifyBranches(exprTy, Type::Void));
4519
        },
4520
        case ast::NodeValue::TypeSig(sig) => return try inferTypeSig(self, node, sig),
4521
        case ast::NodeValue::Super => {
4522
            // `super` by itself is invalid, must be used in scope access.
4523
            throw emitError(self, node, ErrorKind::InvalidModulePath);
4524
        },
4525
        case ast::NodeValue::Nil => {
4526
            // Use the hint type if it's an optional, otherwise fall back to `Nil`.
4527
            if let case Type::Optional(_) = hint {
4528
                return setNodeType(self, node, hint);
4529
            }
4530
            return setNodeType(self, node, Type::Nil);
4531
        },
4532
        case ast::NodeValue::Undef => {
4533
            return setNodeType(self, node, Type::Undefined);
4534
        },
4535
        case ast::NodeValue::Bool(value) => {
4536
            setNodeConstValue(self, node, ConstValue::Bool(value));
4537
            return setNodeType(self, node, Type::Bool);
4538
        }
4539
        case ast::NodeValue::Char(value) => {
4540
            setNodeConstValue(self, node, ConstValue::Char(value));
4541
            return setNodeType(self, node, Type::U8);
4542
        }
4543
        case ast::NodeValue::String(text) => {
4544
            setNodeConstValue(self, node, ConstValue::String(text));
4545
            let byteTy = allocType(self, Type::U8);
4546
            let sliceTy = allocType(self, Type::Slice(SliceType {
4547
                class: types::PointerClass::Owned,
4548
                item: byteTy,
4549
                mutable: false,
4550
            }));
4551
            return setNodeType(self, node, *sliceTy);
4552
        },
4553
        case ast::NodeValue::Number(lit) => {
4554
            setNodeConstValue(self, node, ConstValue::Int(ConstInt {
4555
                magnitude: lit.magnitude,
4556
                bits: 64,
4557
                signed: false,
4558
                negative: false,
4559
            }));
4560
            return setNodeType(self, node, Type::Int);
4561
        },
4562
        case ast::NodeValue::Placeholder => {
4563
            return setNodeType(self, node, hint);
4564
        },
4565
        else => {
4566
            throw emitError(self, node, ErrorKind::UnexpectedNode(node));
4567
        }
4568
    }
4569
}
4570
4571
/// Visit an optional node when present.
4572
fn visitOptional(self: *mut Resolver, node: ?*ast::Node, hint: Type) -> ?Type
4573
    throws (ResolveError)
4574
{
4575
    if let n = node {
4576
        return try visit(self, n, hint);
4577
    }
4578
    return nil;
4579
}
4580
4581
/// Visit every node contained in a list, returning the last resolved type.
4582
fn visitList(self: *mut Resolver, list: *mut [*ast::Node]) -> Type
4583
    throws (ResolveError)
4584
{
4585
    let mut diverges = false;
4586
    for item in list {
4587
        if try infer(self, item) == Type::Never {
4588
            set diverges = true;
4589
        }
4590
    }
4591
    if diverges {
4592
        return Type::Never;
4593
    }
4594
    return Type::Void;
4595
}
4596
4597
/// Collect attribute flags applied to a declaration.
4598
fn resolveAttributes(self: *mut Resolver, attrs: ?ast::Attributes) -> u32 {
4599
    let list = attrs else return 0;
4600
    let attrNodes = list.list;
4601
    let mut mask: u32 = 0;
4602
4603
    for node in attrNodes {
4604
        let case ast::NodeValue::Attribute(attr) = node.value
4605
            else panic "resolveAttributes: invalid attribute node";
4606
        set mask |= (attr as u32);
4607
    }
4608
    return mask;
4609
}
4610
4611
/// Ensure the `default` attribute is only applied to functions.
4612
fn ensureDefaultAttrNotAllowed(self: *mut Resolver, node: *ast::Node, attrs: u32)
4613
    throws (ResolveError)
4614
{
4615
    let defaultBit = ast::Attribute::Default as u32;
4616
    if (attrs & defaultBit) <> 0 {
4617
        throw emitError(self, node, ErrorKind::DefaultAttrOnlyOnFn);
4618
    }
4619
}
4620
4621
/// Analyze a block node, allocating a nested lexical scope.
4622
fn resolveBlock(self: *mut Resolver, node: *ast::Node, block: ast::Block) -> Type
4623
    throws (ResolveError)
4624
{
4625
    enterScope(self, node);
4626
    let blockTy = try visitList(self, block.statements) catch {
4627
        // One of the statements in the block failed analysis. We simply proceed
4628
        // without checking the rest of the block statements. Return `Never` to
4629
        // avoid spurious `FnMissingReturn` errors.
4630
        exitScope(self);
4631
        return setNodeType(self, node, Type::Never);
4632
    };
4633
    exitScope(self);
4634
4635
    return setNodeType(self, node, blockTy);
4636
}
4637
4638
/// Analyze a `let` declaration and bind its identifier.
4639
fn resolveLet(self: *mut Resolver, node: *ast::Node, decl: ast::Let) -> Type
4640
    throws (ResolveError)
4641
{
4642
    let mut alignment: u32 = 0; // Zero is default.
4643
    let mut bindingTy = Type::Unknown;
4644
4645
    // Check type.
4646
    if let declTy = try visitOptional(self, decl.type, Type::Unknown) {
4647
        let _coercion = try checkAssignable(self, decl.value, declTy);
4648
        set bindingTy = declTy;
4649
    } else {
4650
        set bindingTy = try infer(self, decl.value);
4651
4652
        if not isTypeInferrable(bindingTy) {
4653
            throw emitError(self, decl.value, ErrorKind::CannotInferType);
4654
        }
4655
    }
4656
    // Variables cannot have void type.
4657
    if containsRef(bindingTy) {
4658
        throw emitError(self, node, ErrorKind::RefBinding);
4659
    }
4660
    if bindingTy == Type::Void {
4661
        throw emitError(self, decl.value, ErrorKind::CannotAssignVoid);
4662
    }
4663
    // Variables cannot have opaque type directly.
4664
    if bindingTy == Type::Opaque {
4665
        throw emitError(self, node, ErrorKind::OpaqueTypeNotAllowed);
4666
    }
4667
    // Check alignment.
4668
    if let a = decl.alignment {
4669
        let case ast::NodeValue::Align { value } = a.value
4670
            else panic "resolveLet: expected Align node";
4671
        set alignment = try checkSizeInt(self, value);
4672
    }
4673
    assert bindingTy <> Type::Unknown;
4674
4675
    // Alignment must be zero or a power of two.
4676
    if alignment <> 0 and (alignment & (alignment - 1)) <> 0 {
4677
        throw emitError(self, decl.value, ErrorKind::InvalidAlignmentValue(alignment));
4678
    }
4679
    let _ = try bindValueIdent(self, decl.ident, node, bindingTy, decl.mutable, alignment, 0);
4680
    setNodeType(self, decl.value, bindingTy);
4681
4682
    return Type::Void;
4683
}
4684
4685
/// Check whether a node is an integer literal, optionally under unary negation.
4686
fn isIntegerLiteralExpr(node: *ast::Node) -> bool {
4687
    match node.value {
4688
        case ast::NodeValue::Number(_) => return true,
4689
        case ast::NodeValue::UnOp(unop) => {
4690
            if unop.op == ast::UnaryOp::Neg {
4691
                return isIntegerLiteralExpr(unop.value);
4692
            }
4693
            return false;
4694
        },
4695
        else => return false,
4696
    }
4697
}
4698
4699
/// Determine whether a node represents a compile-time constant expression.
4700
export fn isConstExpr(self: *Resolver, node: *ast::Node) -> bool {
4701
    match node.value {
4702
        case ast::NodeValue::Bool(_),
4703
             ast::NodeValue::Char(_),
4704
             ast::NodeValue::Number(_),
4705
             ast::NodeValue::String(_),
4706
             ast::NodeValue::Undef,
4707
             ast::NodeValue::Nil => {
4708
            return true;
4709
        },
4710
        case ast::NodeValue::ArrayLit(items) => {
4711
            for item in items {
4712
                if not isConstExpr(self, item) {
4713
                    return false;
4714
                }
4715
            }
4716
            return true;
4717
        },
4718
        case ast::NodeValue::ArrayRepeatLit(repeat) => {
4719
            return isConstExpr(self, repeat.item);
4720
        },
4721
        case ast::NodeValue::AddressOf(addr) => {
4722
            let ty = typeFor(self, node) else {
4723
                return false;
4724
            };
4725
            if let case Type::Slice(_) = ty {
4726
                return isConstExpr(self, addr.target);
4727
            }
4728
            return false;
4729
        },
4730
        case ast::NodeValue::RecordLit(lit) => {
4731
            // Record literals are constant if all field values are constant.
4732
            for field in lit.fields {
4733
                if let case ast::NodeValue::RecordLitField(fieldLit) = field.value {
4734
                    if not isConstExpr(self, fieldLit.value) {
4735
                        return false;
4736
                    }
4737
                }
4738
            }
4739
            return true;
4740
        },
4741
        case ast::NodeValue::Ident(_),
4742
             ast::NodeValue::ScopeAccess(_) => {
4743
            // Identifiers and scope accesses referencing constants, union
4744
            // variants, or function values are constant expressions.
4745
            if let sym = symbolFor(self, node) {
4746
                match sym.data {
4747
                    case SymbolData::Variant { .. },
4748
                         SymbolData::Constant { .. },
4749
                         SymbolData::ConstParameter(_) => return true,
4750
                    case SymbolData::Value { type, .. } => {
4751
                        if let case Type::Fn(_) = type {
4752
                            return true;
4753
                        }
4754
                    }
4755
                    else => {}
4756
                }
4757
            }
4758
            return false;
4759
        },
4760
        case ast::NodeValue::Call(call) => {
4761
            // Constructor calls (union variants, unlabeled records) are constant
4762
            // if all payload args are themselves constant.
4763
            if let sym = symbolFor(self, call.callee) {
4764
                match sym.data {
4765
                    case SymbolData::Variant { .. } => {}
4766
                    case SymbolData::Type(NominalType::Record(recInfo)) => {
4767
                        if recInfo.labeled {
4768
                            return false;
4769
                        }
4770
                    },
4771
                    else => return false,
4772
                }
4773
                for arg in call.args {
4774
                    if not isConstExpr(self, arg) {
4775
                        return false;
4776
                    }
4777
                }
4778
                return true;
4779
            }
4780
            return false;
4781
        },
4782
        case ast::NodeValue::BinOp(binop) => {
4783
            // Binary expressions are constant if both operands are constant.
4784
            return isConstExpr(self, binop.left) and isConstExpr(self, binop.right);
4785
        },
4786
        case ast::NodeValue::UnOp(unop) => {
4787
            // Unary expressions are constant if the operand is constant.
4788
            return isConstExpr(self, unop.value);
4789
        },
4790
        case ast::NodeValue::As(expr) => {
4791
            // Cast expressions are constant if the source value is constant.
4792
            return isConstExpr(self, expr.value);
4793
        },
4794
        else => {
4795
            return false;
4796
        }
4797
    }
4798
}
4799
4800
/// Construct an integer constant descriptor.
4801
fn constInt(magnitude: u64, bits: u8, signed: bool, negative: bool) -> ConstValue {
4802
    return ConstValue::Int(ConstInt { magnitude, bits, signed, negative });
4803
}
4804
4805
/// Apply an integer cast to a constant value, including target-width
4806
/// truncation and signed interpretation.
4807
fn castConstInt(value: ConstInt, target: Type) -> ConstValue {
4808
    let raw = constIntToBits(value);
4809
    let range = integerRange(target)
4810
        else panic "castConstInt: expected integer type";
4811
4812
    match range {
4813
        case IntegerRange::Unsigned { bits, .. } =>
4814
            return ConstValue::Int(constIntFromBits(raw, bits, false)),
4815
        case IntegerRange::Signed { bits, .. } =>
4816
            return ConstValue::Int(constIntFromBits(raw, bits, true)),
4817
    }
4818
}
4819
4820
/// Return whether a constant expression depends on a rigid constant parameter.
4821
fn containsGenericConstExpr(self: *Resolver, node: *ast::Node) -> bool {
4822
    match node.value {
4823
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) => {
4824
            let sym = symbolFor(self, node) else return false;
4825
            if let case SymbolData::ConstParameter(_) = sym.data {
4826
                return true;
4827
            }
4828
            return false;
4829
        }
4830
        case ast::NodeValue::BinOp(binop) =>
4831
            return containsGenericConstExpr(self, binop.left) or
4832
                   containsGenericConstExpr(self, binop.right),
4833
        case ast::NodeValue::UnOp(unop) =>
4834
            return containsGenericConstExpr(self, unop.value),
4835
        case ast::NodeValue::As(expr) =>
4836
            return containsGenericConstExpr(self, expr.value),
4837
        else => return false,
4838
    }
4839
}
4840
4841
/// Evaluate an integer constant expression after replacing rigid parameters.
4842
fn constValueWithSubstitution(
4843
    self: *mut Resolver,
4844
    node: *ast::Node,
4845
    sub: *Substitution,
4846
) -> ?ConstValue {
4847
    if let value = constValueEntry(self, node) {
4848
        return value;
4849
    }
4850
    match node.value {
4851
        case ast::NodeValue::Ident(_), ast::NodeValue::ScopeAccess(_) => {
4852
            let sym = symbolFor(self, node) else return nil;
4853
            let case SymbolData::ConstParameter(param) = sym.data else return nil;
4854
            let arg = substitutionArg(sub, param);
4855
            let case Type::ConstArgument { value, .. } = arg else return nil;
4856
            return ConstValue::Int(value);
4857
        }
4858
        case ast::NodeValue::BinOp(binop) => {
4859
            let left = constValueWithSubstitution(self, binop.left, sub)
4860
                else return nil;
4861
            let right = constValueWithSubstitution(self, binop.right, sub)
4862
                else return nil;
4863
            let case ConstValue::Int(leftInt) = left else return nil;
4864
            let case ConstValue::Int(rightInt) = right else return nil;
4865
            return foldIntBinOp(binop.op, leftInt, rightInt);
4866
        }
4867
        case ast::NodeValue::UnOp(unop) => {
4868
            let value = constValueWithSubstitution(self, unop.value, sub)
4869
                else return nil;
4870
            match unop.op {
4871
                case ast::UnaryOp::Not => {
4872
                    let case ConstValue::Bool(v) = value else return nil;
4873
                    return ConstValue::Bool(not v);
4874
                }
4875
                case ast::UnaryOp::Neg => {
4876
                    let case ConstValue::Int(v) = value else return nil;
4877
                    return constInt(v.magnitude, v.bits, true, not v.negative);
4878
                }
4879
                case ast::UnaryOp::BitNot => {
4880
                    let case ConstValue::Int(v) = value else return nil;
4881
                    return ConstValue::Int(
4882
                        constIntFromSigned(
4883
                            -(constIntToSigned(v) + 1), v.bits, v.signed
4884
                        )
4885
                    );
4886
                }
4887
            }
4888
        }
4889
        case ast::NodeValue::As(expr) => {
4890
            let value = constValueWithSubstitution(self, expr.value, sub)
4891
                else return nil;
4892
            let case ConstValue::Int(v) = value else return nil;
4893
            let target = typeFor(self, node) else return nil;
4894
            if integerRange(target) == nil {
4895
                return nil;
4896
            }
4897
            return castConstInt(v, target);
4898
        }
4899
        else => return nil,
4900
    }
4901
}
4902
4903
/// Return the constant `u32` value for a slice bound when known.
4904
fn constSliceIndex(self: *mut Resolver, node: *ast::Node) -> ?u32 {
4905
    let value = constValueEntry(self, node)
4906
        else return nil;
4907
    let case ConstValue::Int(int) = value
4908
        else return nil;
4909
    if int.negative {
4910
        return nil;
4911
    }
4912
    return int.magnitude as u32;
4913
}
4914
4915
/// Validates and extracts a non-negative integer constant from a compile-time expression.
4916
///
4917
/// This function ensures that a node represents a valid, non-negative integer constant
4918
/// that fits within a machine word. It is used for contexts requiring compile-time
4919
/// non-negative integers, such as array sizes and alignment specifications.
4920
///
4921
/// Returns the unsigned magnitude of the constant as `u32`.
4922
fn checkSizeInt(self: *mut Resolver, node: *ast::Node) -> u32
4923
    throws (ResolveError)
4924
{
4925
    // First traverse the node expect a numeric type.
4926
    let _ = try checkNumeric(self, node);
4927
4928
    // Look up the compile-time constant value associated with this node.
4929
    let value = constValueEntry(self, node)
4930
        else throw emitError(self, node, ErrorKind::ConstExprRequired);
4931
4932
    let case ConstValue::Int(int) = value
4933
        else panic "checkSizeInt: expected integer constant";
4934
4935
    // Validate it fits within u32 range.
4936
    if not validateConstIntRange(value, Type::U32) {
4937
        throw emitError(self, node, ErrorKind::NumericLiteralOverflow);
4938
    }
4939
    assert not int.negative;
4940
    setNodeType(self, node, Type::U32);
4941
4942
    return int.magnitude as u32;
4943
}
4944
4945
/// Check that constructor arguments match record fields.
4946
///
4947
/// Verifies argument count matches field count, and that each argument is
4948
/// assignable to its corresponding field type.
4949
fn checkRecordConstructorArgs(self: *mut Resolver, node: *ast::Node, args: *mut [*ast::Node], recInfo: RecordType)
4950
    throws (ResolveError)
4951
{
4952
    try checkRecordArity(self, args, recInfo, node);
4953
    for arg, i in args {
4954
        let fieldType = recInfo.fields[i].fieldType;
4955
        try checkAssignable(self, arg, fieldType);
4956
    }
4957
}
4958
4959
/// Check that the argument count of a constructor pattern or call matches the record field count.
4960
fn checkRecordArity(self: *mut Resolver, args: *mut [*ast::Node], recInfo: RecordType, pattern: *ast::Node) throws (ResolveError) {
4961
    if args.len <> recInfo.fields.len {
4962
        throw emitError(self, pattern, ErrorKind::RecordFieldCountMismatch(CountMismatch {
4963
            expected: recInfo.fields.len as u32,
4964
            actual: args.len,
4965
        }));
4966
    }
4967
}
4968
4969
/// Helper for analyzing `constant` and `static` declarations.
4970
fn resolveConstOrStatic(
4971
    self: *mut Resolver,
4972
    node: *ast::Node,
4973
    ident: *ast::Node,
4974
    typeNode: *ast::Node,
4975
    valueNode: *ast::Node,
4976
    attrList: ?ast::Attributes,
4977
    isConst: bool
4978
) -> Type throws (ResolveError) {
4979
    let attrs = resolveAttributes(self, attrList);
4980
    let bindingTy = try infer(self, typeNode);
4981
    try ensureStorableType(self, typeNode, bindingTy);
4982
    let valueTy = try checkAssignable(self, valueNode, bindingTy);
4983
4984
    if isConst {
4985
        let mut constVal = constValueEntry(self, valueNode);
4986
        if constVal == nil and not isConstExpr(self, valueNode) {
4987
            throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
4988
        }
4989
        if let val = constVal {
4990
            if let case ConstValue::Int(int) = val; isNumericType(bindingTy) {
4991
                set constVal = castConstInt(int, bindingTy);
4992
            }
4993
        }
4994
        try bindConstIdent(self, ident, node, bindingTy, constVal, attrs);
4995
    } else {
4996
        if not isConstExpr(self, valueNode) {
4997
            throw emitError(self, valueNode, ErrorKind::ConstExprRequired);
4998
        }
4999
        try bindValueIdent(self, ident, node, bindingTy, true, 0, attrs);
5000
    }
5001
    setNodeType(self, valueNode, bindingTy);
5002
5003
    return Type::Void;
5004
}
5005
5006
/// Bind one declaration's rigid generic parameters in its child scope.
5007
fn resolveGenericParams(
5008
    self: *mut Resolver,
5009
    owner: *ast::Node,
5010
    nodes: *mut [*ast::Node],
5011
) -> *[*GenericParamType] throws (ResolveError) {
5012
    if nodes.len > MAX_GENERIC_PARAMS {
5013
        throw emitError(self, owner, ErrorKind::GenericParameterLimit);
5014
    }
5015
    let a = alloc::arenaAllocator(&mut self.arena);
5016
    let mut result: *mut [*GenericParamType] = &mut [];
5017
    for paramNode, index in nodes {
5018
        let case ast::NodeValue::GenericParam(param) = paramNode.value
5019
            else throw emitError(self, paramNode, ErrorKind::Internal);
5020
        let mut paramName: *[u8] = undefined;
5021
        let mut nameNode: *ast::Node = undefined;
5022
        let mut traitBounds: *mut [*TraitType] = &mut [];
5023
        let mut constType: ?*Type = nil;
5024
        match param {
5025
            case ast::GenericParam::Const { name, type } => {
5026
                set nameNode = name;
5027
                set paramName = try nodeName(self, name);
5028
                let ty = try resolveValueType(self, type);
5029
                if integerRange(ty) == nil or ty == Type::Int {
5030
                    throw emitError(self, type, ErrorKind::GenericConstUnsupported);
5031
                }
5032
                set constType = allocType(self, ty);
5033
            }
5034
            case ast::GenericParam::Type { name, bounds } => {
5035
                set nameNode = name;
5036
                set paramName = try nodeName(self, name);
5037
                for bound in bounds {
5038
                    let boundSym = try resolveNamePath(self, bound);
5039
                    let case SymbolData::Trait(traitInfo) = boundSym.data else {
5040
                        throw emitError(self, bound, ErrorKind::GenericBoundNotTrait);
5041
                    };
5042
                    setNodeSymbol(self, bound, boundSym);
5043
                    traitBounds.append(traitInfo, a);
5044
                }
5045
            }
5046
        }
5047
        let used = try! alloc::alloc(
5048
            &mut self.arena, @sizeOf(bool), @alignOf(bool)
5049
        ) as *mut bool;
5050
        set *used = false;
5051
        let p = try! alloc::alloc(
5052
            &mut self.arena,
5053
            @sizeOf(GenericParamType),
5054
            @alignOf(GenericParamType),
5055
        ) as *mut GenericParamType;
5056
        set *p = GenericParamType {
5057
            owner,
5058
            node: paramNode,
5059
            name: paramName,
5060
            index,
5061
            bounds: &traitBounds[..],
5062
            used,
5063
            constType,
5064
        };
5065
        let data = SymbolData::ConstParameter(p) if constType <> nil
5066
            else SymbolData::TypeParameter(p);
5067
        let sym = try bindIdent(
5068
            self, paramName, paramNode, data, 0, self.scope
5069
        );
5070
        setNodeSymbol(self, nameNode, sym);
5071
        if let ty = constType {
5072
            setNodeType(self, nameNode, *ty);
5073
            setNodeType(self, paramNode, *ty);
5074
        } else {
5075
            setNodeType(self, nameNode, Type::Parameter(p));
5076
            setNodeType(self, paramNode, Type::Parameter(p));
5077
        }
5078
        result.append(p, a);
5079
    }
5080
    return &result[..];
5081
}
5082
5083
/// Retrieve sparse metadata for a generic declaration symbol.
5084
export fn genericTemplateFor(self: *Resolver, symbol: *Symbol) -> ?*GenericTemplate {
5085
    let mut cursor = self.genericTemplates;
5086
    while let entry = cursor {
5087
        if entry.symbol == symbol {
5088
            return &entry.template;
5089
        }
5090
        set cursor = entry.next;
5091
    }
5092
    return nil;
5093
}
5094
5095
/// Retrieve mutable metadata while checking a generic function body.
5096
fn genericTemplateForMut(
5097
    self: *mut Resolver,
5098
    symbol: *Symbol,
5099
) -> ?*mut GenericTemplate {
5100
    let mut cursor = self.genericTemplates;
5101
    while let entry = cursor {
5102
        if entry.symbol == symbol {
5103
            return &mut entry.template;
5104
        }
5105
        set cursor = entry.next;
5106
    }
5107
    return nil;
5108
}
5109
5110
/// Return the generic template whose symbolic body is currently being checked.
5111
fn currentGenericTemplateSymbol(self: *Resolver) -> ?*mut Symbol {
5112
    let current = self.currentFn else return nil;
5113
    let mut cursor = self.genericTemplates;
5114
    while let entry = cursor {
5115
        if let signature = entry.template.signature; signature == current {
5116
            return entry.symbol;
5117
        }
5118
        set cursor = entry.next;
5119
    }
5120
    return nil;
5121
}
5122
5123
/// Attach generic metadata without increasing every symbol's allocation.
5124
fn registerGenericTemplate(
5125
    self: *mut Resolver,
5126
    symbol: *mut Symbol,
5127
    template: GenericTemplate,
5128
) -> *mut GenericTemplate {
5129
    let entry = try! alloc::alloc(
5130
        &mut self.arena,
5131
        @sizeOf(GenericTemplateNode),
5132
        @alignOf(GenericTemplateNode),
5133
    ) as *mut GenericTemplateNode;
5134
    set *entry = GenericTemplateNode {
5135
        symbol,
5136
        template,
5137
        next: self.genericTemplates,
5138
    };
5139
    set self.genericTemplates = entry;
5140
    return &mut entry.template;
5141
}
5142
5143
/// Resolve a function signature type without laying out generic aggregates.
5144
fn resolveFnSignatureType(self: *mut Resolver, node: *ast::Node, generic: bool) -> Type
5145
    throws (ResolveError)
5146
{
5147
    if generic {
5148
        return try resolveGenericValueType(self, node);
5149
    }
5150
    return try infer(self, node);
5151
}
5152
5153
/// Resolve and bind a function parameter using its signature mode.
5154
fn resolveFnSignatureParam(self: *mut Resolver, node: *ast::Node, generic: bool) -> Type
5155
    throws (ResolveError)
5156
{
5157
    if not generic {
5158
        return try infer(self, node);
5159
    }
5160
    let case ast::NodeValue::FnParam(param) = node.value
5161
        else throw emitError(self, node, ErrorKind::Internal);
5162
    let ty = try resolveGenericValueType(self, param.type);
5163
    let _ = try bindValueIdent(self, param.name, node, ty, false, 0, 0);
5164
    return setNodeType(self, node, ty);
5165
}
5166
5167
/// Analyze a function declaration signature and bind the function name.
5168
fn resolveFnDecl(self: *mut Resolver, node: *ast::Node, decl: ast::FnDecl) -> Type
5169
    throws (ResolveError)
5170
{
5171
    let attrMask = resolveAttributes(self, decl.attrs);
5172
    if decl.params.len > 0 {
5173
        if self.currentFn <> nil {
5174
            throw emitError(self, node, ErrorKind::GenericFnNested);
5175
        }
5176
        if ast::hasAttribute(attrMask, ast::Attribute::Extern)
5177
            or ast::hasAttribute(attrMask, ast::Attribute::Default)
5178
            or ast::hasAttribute(attrMask, ast::Attribute::Intrinsic)
5179
        {
5180
            throw emitError(self, node, ErrorKind::GenericFnAttribute);
5181
        }
5182
    }
5183
    let a = alloc::arenaAllocator(&mut self.arena);
5184
    let mut paramTypes: *mut [*Type] = &mut [];
5185
    let mut throwList: *mut [*Type] = &mut [];
5186
    let mut fnType = FnType {
5187
        paramTypes: &[],
5188
        returnType: allocType(self, Type::Void),
5189
        throwList: &[],
5190
        isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe),
5191
        localCount: 0,
5192
    };
5193
    enterFn(self, node, &fnType);
5194
    let genericParams = try resolveGenericParams(self, node, decl.params) catch e {
5195
        exitFn(self);
5196
        throw e;
5197
    };
5198
    if let retNode = decl.sig.returnType {
5199
        let retTy = try resolveFnSignatureType(
5200
            self, retNode, genericParams.len > 0
5201
        ) catch e {
5202
            exitFn(self);
5203
            throw e;
5204
        };
5205
        try ensureStorableType(self, retNode, retTy) catch e {
5206
            exitFn(self);
5207
            throw e;
5208
        };
5209
        set fnType.returnType = allocType(self, retTy);
5210
    }
5211
    if decl.sig.params.len > MAX_FN_PARAMS {
5212
        exitFn(self);
5213
        throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
5214
            expected: MAX_FN_PARAMS,
5215
            actual: decl.sig.params.len,
5216
        }));
5217
    }
5218
    for paramNode in decl.sig.params {
5219
        let paramTy = try resolveFnSignatureParam(
5220
            self, paramNode, genericParams.len > 0
5221
        ) catch e {
5222
            exitFn(self);
5223
            throw e;
5224
        };
5225
        paramTypes.append(allocType(self, paramTy), a);
5226
    }
5227
    if decl.sig.throwList.len > MAX_FN_THROWS {
5228
        exitFn(self);
5229
        throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch {
5230
            expected: MAX_FN_THROWS,
5231
            actual: decl.sig.throwList.len,
5232
        }));
5233
    }
5234
    for throwNode in decl.sig.throwList {
5235
        let throwTy = try resolveFnSignatureType(
5236
            self, throwNode, genericParams.len > 0
5237
        ) catch e {
5238
            exitFn(self);
5239
            throw e;
5240
        };
5241
        try ensureStorableType(self, throwNode, throwTy) catch e {
5242
            exitFn(self);
5243
            throw e;
5244
        };
5245
        throwList.append(allocType(self, throwTy), a);
5246
    }
5247
    exitFn(self);
5248
    set fnType.paramTypes = &paramTypes[..];
5249
    set fnType.throwList = &throwList[..];
5250
5251
    let fnInfo = allocFnType(self, fnType);
5252
    let ty = Type::Fn(fnInfo);
5253
    let sym = try bindValueIdent(self, decl.name, node, ty, false, 0, attrMask)
5254
        else throw emitError(self, node, ErrorKind::ExpectedIdentifier);
5255
    if genericParams.len > 0 {
5256
        registerGenericTemplate(self, sym, GenericTemplate {
5257
            decl: node,
5258
            params: genericParams,
5259
            signature: fnInfo,
5260
            members: &[],
5261
            declaredLinear: false,
5262
            moduleId: sym.moduleId,
5263
            bodyResolved: false,
5264
            bodyChecks: 0,
5265
        });
5266
    }
5267
    return ty;
5268
}
5269
5270
/// Analyze a function body.
5271
fn resolveFnDeclBody(self: *mut Resolver, node: *ast::Node, decl: ast::FnDecl) throws (ResolveError) {
5272
    let sym = symbolFor(self, node) else {
5273
        // The function declaration failed to type check, therefore
5274
        // no symbol was associated with it.
5275
        return;
5276
    };
5277
    let generic = genericTemplateForMut(self, sym);
5278
    if let template = generic {
5279
        if template.bodyResolved {
5280
            return;
5281
        }
5282
        set template.bodyResolved = true;
5283
        set template.bodyChecks += 1;
5284
    }
5285
    let case SymbolData::Value { type: Type::Fn(fnType), .. } = sym.data else {
5286
        panic "resolveFnDeclBody: unexpected symbol data for function";
5287
    };
5288
    let retTy = *fnType.returnType;
5289
    let isExtern = ast::hasAttribute(sym.attrs, ast::Attribute::Extern);
5290
    let isIntrinsic = ast::hasAttribute(sym.attrs, ast::Attribute::Intrinsic);
5291
    let isUnsafe = fnType.isUnsafe;
5292
5293
    if let body = decl.body {
5294
        if isIntrinsic {
5295
            throw emitError(self, node, ErrorKind::IntrinsicUnexpectedBody);
5296
        }
5297
        if isExtern {
5298
            throw emitError(self, node, ErrorKind::FnUnexpectedBody);
5299
        }
5300
        if isUnsafe {
5301
            set self.unsafeDepth += 1;
5302
        }
5303
        enterFn(self, node, fnType); // Enter function scope for body analysis.
5304
5305
        let bodyTy = try checkAssignable(self, body, Type::Void) catch e {
5306
            exitFn(self);
5307
            if isUnsafe { set self.unsafeDepth -= 1; }
5308
            throw e;
5309
        };
5310
        if retTy <> Type::Void and bodyTy <> Type::Never {
5311
            exitFn(self);
5312
            if isUnsafe { set self.unsafeDepth -= 1; }
5313
            throw emitError(self, body, ErrorKind::FnMissingReturn);
5314
        }
5315
        exitFn(self);
5316
        if isUnsafe {
5317
            set self.unsafeDepth -= 1;
5318
        }
5319
        if self.linearEnabled {
5320
            try checkLinearFn(self, nil, decl.sig.params, body);
5321
        }
5322
        if let template = generic {
5323
            for param in template.params {
5324
                if not *param.used {
5325
                    throw emitError(
5326
                        self,
5327
                        param.node,
5328
                        ErrorKind::GenericFnUnusedParameter(param.name),
5329
                    );
5330
                }
5331
            }
5332
        }
5333
    } else if not isExtern {
5334
        throw emitError(self, node, ErrorKind::FnMissingBody);
5335
    }
5336
}
5337
5338
/// Analyze a function parameter and bind its identifier.
5339
fn resolveFnParam(self: *mut Resolver, node: *ast::Node, param: ast::FnParam) -> Type
5340
    throws (ResolveError)
5341
{
5342
    let ty = try resolveValueType(self, param.type);
5343
    let _ = try bindValueIdent(self, param.name, node, ty, false, 0, 0);
5344
5345
    return ty;
5346
}
5347
5348
/// Resolve the compiler-known `Linear` marker from a derive list.
5349
fn resolveLinearDerive(self: *mut Resolver, derives: *mut [*ast::Node]) -> bool
5350
    throws (ResolveError)
5351
{
5352
    let mut linear = false;
5353
    for derive in derives {
5354
        let name = try nodeName(self, derive);
5355
        if mem::eq(name, "Linear") {
5356
            if linear {
5357
                throw emitError(self, derive, ErrorKind::DuplicateBinding(name));
5358
            }
5359
            set linear = true;
5360
            set self.linearEnabled = true;
5361
        } else {
5362
            // Other derives retain their existing trait-name validation.
5363
            try infer(self, derive);
5364
        }
5365
    }
5366
    return linear;
5367
}
5368
5369
/// Resolve a type used in generic data without requiring aggregate layout.
5370
fn resolveGenericValueType(self: *mut Resolver, node: *ast::Node) -> Type
5371
    throws (ResolveError)
5372
{
5373
    let case ast::NodeValue::TypeSig(sig) = node.value
5374
        else return try resolveValueType(self, node);
5375
    let mut ty: Type = undefined;
5376
    match sig {
5377
        case ast::TypeSig::Array { itemType, length } => {
5378
            let item = try resolveGenericValueType(self, itemType);
5379
            let _ = try checkNumeric(self, length);
5380
            if let value = constValueEntry(self, length) {
5381
                if not validateConstIntRange(value, Type::U32) {
5382
                    throw emitError(self, length, ErrorKind::NumericLiteralOverflow);
5383
                }
5384
                let case ConstValue::Int(int) = value
5385
                    else throw emitError(self, length, ErrorKind::ConstExprRequired);
5386
                set ty = Type::Array(ArrayType {
5387
                    item: allocType(self, item),
5388
                    length: int.magnitude as u32,
5389
                });
5390
            } else if isConstExpr(self, length) and
5391
                      containsGenericConstExpr(self, length)
5392
            {
5393
                set ty = Type::GenericArray {
5394
                    item: allocType(self, item),
5395
                    length,
5396
                };
5397
            } else {
5398
                throw emitError(self, length, ErrorKind::ConstExprRequired);
5399
            }
5400
        }
5401
        case ast::TypeSig::Slice { class, itemType, mutable } => {
5402
            let item = try resolveGenericValueType(self, itemType);
5403
            set ty = Type::Slice(SliceType {
5404
                class,
5405
                item: allocType(self, item),
5406
                mutable,
5407
            });
5408
        }
5409
        case ast::TypeSig::Pointer { class, valueType, mutable } => {
5410
            let target = try resolveGenericValueType(self, valueType);
5411
            set ty = Type::Pointer(PointerType {
5412
                class,
5413
                target: allocType(self, target),
5414
                mutable,
5415
            });
5416
        }
5417
        case ast::TypeSig::Optional { valueType } => {
5418
            let payload = try resolveGenericValueType(self, valueType);
5419
            set ty = Type::Optional(allocType(self, payload));
5420
        }
5421
        case ast::TypeSig::Nominal(typeName) => {
5422
            let case ast::NodeValue::GenericApply(app) = typeName.value
5423
                else return try resolveValueType(self, node);
5424
            let templateSym = try resolveGenericDataTarget(self, app.target);
5425
            try ensureGenericDataTemplate(self, templateSym);
5426
            let template = genericTemplateFor(self, templateSym)
5427
                else throw emitError(self, typeName, ErrorKind::Internal);
5428
            if app.args.len <> template.params.len {
5429
                throw emitError(self, typeName, ErrorKind::GenericArgumentCount(
5430
                    CountMismatch {
5431
                        expected: template.params.len,
5432
                        actual: app.args.len,
5433
                    }
5434
                ));
5435
            }
5436
            let a = alloc::arenaAllocator(&mut self.arena);
5437
            let mut args: *mut [*Type] = &mut [];
5438
            for argNode, i in app.args {
5439
                let arg = try resolveGenericArgument(
5440
                    self, argNode, template.params[i]
5441
                );
5442
                args.append(allocType(self, arg), a);
5443
            }
5444
            let symbolic = try! alloc::alloc(
5445
                &mut self.arena,
5446
                @sizeOf(GenericDataApplyType),
5447
                @alignOf(GenericDataApplyType),
5448
            ) as *mut GenericDataApplyType;
5449
            set *symbolic = GenericDataApplyType {
5450
                template: templateSym,
5451
                args: &args[..],
5452
                site: typeName,
5453
            };
5454
            set ty = Type::GenericDataApply(symbolic);
5455
        }
5456
        case ast::TypeSig::Record { fields, labeled } => {
5457
            let a = alloc::arenaAllocator(&mut self.arena);
5458
            let mut result: *mut [RecordField] = &mut [];
5459
            for field in fields {
5460
                let case ast::NodeValue::RecordField {
5461
                    field: fieldNameNode,
5462
                    type: typeNode,
5463
                    value,
5464
                } = field.value else panic "resolveGenericValueType: invalid record field";
5465
                let fieldType = try resolveGenericValueType(self, typeNode);
5466
                try ensureStorableType(self, typeNode, fieldType);
5467
                if let initializer = value {
5468
                    let _ = try checkAssignable(self, initializer, fieldType);
5469
                }
5470
                let mut fieldName: ?*[u8] = nil;
5471
                if let name = fieldNameNode {
5472
                    set fieldName = try nodeName(self, name);
5473
                }
5474
                result.append(RecordField {
5475
                    name: fieldName,
5476
                    fieldType,
5477
                    offset: -1,
5478
                }, a);
5479
            }
5480
            let rec = try! alloc::alloc(
5481
                &mut self.arena,
5482
                @sizeOf(GenericRecordType),
5483
                @alignOf(GenericRecordType),
5484
            ) as *mut GenericRecordType;
5485
            set *rec = GenericRecordType {
5486
                fields: &result[..],
5487
                labeled,
5488
            };
5489
            set ty = Type::GenericRecord(rec);
5490
        }
5491
        case ast::TypeSig::Fn(fnSig) => {
5492
            if fnSig.params.len > MAX_FN_PARAMS {
5493
                throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
5494
                    expected: MAX_FN_PARAMS,
5495
                    actual: fnSig.params.len,
5496
                }));
5497
            }
5498
            if fnSig.throwList.len > MAX_FN_THROWS {
5499
                throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch {
5500
                    expected: MAX_FN_THROWS,
5501
                    actual: fnSig.throwList.len,
5502
                }));
5503
            }
5504
            let a = alloc::arenaAllocator(&mut self.arena);
5505
            let mut params: *mut [*Type] = &mut [];
5506
            let mut throwTypes: *mut [*Type] = &mut [];
5507
            for param in fnSig.params {
5508
                let paramType = try resolveGenericValueType(self, param);
5509
                params.append(allocType(self, paramType), a);
5510
            }
5511
            for throwNode in fnSig.throwList {
5512
                let throwType = try resolveGenericValueType(self, throwNode);
5513
                try ensureStorableType(self, throwNode, throwType);
5514
                throwTypes.append(allocType(self, throwType), a);
5515
            }
5516
            let mut returnType = allocType(self, Type::Void);
5517
            if let returnNode = fnSig.returnType {
5518
                let resolved = try resolveGenericValueType(self, returnNode);
5519
                try ensureStorableType(self, returnNode, resolved);
5520
                set returnType = allocType(self, resolved);
5521
            }
5522
            set ty = Type::Fn(allocFnType(self, FnType {
5523
                paramTypes: &params[..],
5524
                returnType,
5525
                throwList: &throwTypes[..],
5526
                isUnsafe: false,
5527
                localCount: 0,
5528
            }));
5529
        }
5530
        else => return try resolveValueType(self, node),
5531
    }
5532
    return setNodeType(self, node, ty);
5533
}
5534
5535
/// Resolve symbolic field or variant types for a generic data template.
5536
fn resolveGenericDataTemplate(
5537
    self: *mut Resolver,
5538
    node: *ast::Node,
5539
    params: *mut [*ast::Node],
5540
    members: *mut [*ast::Node],
5541
    derives: *mut [*ast::Node],
5542
    isRecord: bool,
5543
) throws (ResolveError) {
5544
    let sym = symbolFor(self, node) else return;
5545
    if genericTemplateFor(self, sym) <> nil {
5546
        return;
5547
    }
5548
    enterScope(self, node);
5549
    let genericParams = try resolveGenericParams(self, node, params) catch e {
5550
        exitScope(self);
5551
        throw e;
5552
    };
5553
    let declaredLinear = try resolveLinearDerive(self, derives) catch e {
5554
        exitScope(self);
5555
        throw e;
5556
    };
5557
    // Publish the rigid parameters before resolving members so recursive and
5558
    // mutually recursive applications can observe the in-progress template.
5559
    let metadata = registerGenericTemplate(self, sym, GenericTemplate {
5560
        decl: node,
5561
        params: genericParams,
5562
        signature: nil,
5563
        members: &[],
5564
        declaredLinear,
5565
        moduleId: sym.moduleId,
5566
        bodyResolved: true,
5567
        bodyChecks: 0,
5568
    });
5569
    let a = alloc::arenaAllocator(&mut self.arena);
5570
    let mut memberTypes: *mut [*Type] = &mut [];
5571
    for member in members {
5572
        let mut memberTy = Type::Void;
5573
        let mut defaultValue: ?*ast::Node = nil;
5574
        if isRecord {
5575
            let case ast::NodeValue::RecordField { type, value, .. } = member.value
5576
                else panic "resolveGenericDataTemplate: invalid record field";
5577
            set memberTy = try resolveGenericValueType(self, type) catch e {
5578
                exitScope(self);
5579
                throw e;
5580
            };
5581
            set defaultValue = value;
5582
            try ensureStorableType(self, type, memberTy) catch e {
5583
                exitScope(self);
5584
                throw e;
5585
            };
5586
        } else {
5587
            let case ast::NodeValue::UnionDeclVariant(variant) = member.value
5588
                else panic "resolveGenericDataTemplate: invalid union variant";
5589
            if let type = variant.type {
5590
                set memberTy = try resolveGenericValueType(self, type) catch e {
5591
                    exitScope(self);
5592
                    throw e;
5593
                };
5594
                try ensureStorableType(self, type, memberTy) catch e {
5595
                    exitScope(self);
5596
                    throw e;
5597
                };
5598
            }
5599
            set defaultValue = variant.value;
5600
        }
5601
        if let value = defaultValue {
5602
            if isRecord {
5603
                let _ = try checkAssignable(self, value, memberTy) catch e {
5604
                    exitScope(self);
5605
                    throw e;
5606
                };
5607
            } else {
5608
                let _ = try checkNumeric(self, value) catch e {
5609
                    exitScope(self);
5610
                    throw e;
5611
                };
5612
                if constValueEntry(self, value) == nil and
5613
                   (not isConstExpr(self, value) or
5614
                    not containsGenericConstExpr(self, value))
5615
                {
5616
                    exitScope(self);
5617
                    throw emitError(self, value, ErrorKind::ConstExprRequired);
5618
                }
5619
            }
5620
        }
5621
        memberTypes.append(allocType(self, memberTy), a);
5622
    }
5623
    exitScope(self);
5624
    set *metadata = GenericTemplate {
5625
        decl: node,
5626
        params: genericParams,
5627
        signature: nil,
5628
        members: &memberTypes[..],
5629
        declaredLinear,
5630
        moduleId: sym.moduleId,
5631
        bodyResolved: true,
5632
        bodyChecks: 0,
5633
    };
5634
}
5635
5636
/// Resolve record fields from a node list.
5637
fn resolveRecordFields(self: *mut Resolver, node: *ast::Node, fields: *mut [*ast::Node], labeled: bool) -> RecordType
5638
    throws (ResolveError)
5639
{
5640
    let a = alloc::arenaAllocator(&mut self.arena);
5641
    let mut result: *mut [RecordField] = &mut [];
5642
    let mut currentOffset: u32 = 0;
5643
    let mut maxAlignment: u32 = 1;
5644
5645
    if fields.len > parser::MAX_RECORD_FIELDS {
5646
        throw emitError(self, node, ErrorKind::Internal);
5647
    }
5648
    // TODO: Add cycle detection to catch invalid recursive types like `record A { a: A }`.
5649
    for field in fields {
5650
        let case ast::NodeValue::RecordField {
5651
            field: fieldNode,
5652
            type: typeNode,
5653
            value: valueNode
5654
        } = field.value else panic "resolveRecordFields: invalid record field";
5655
        let fieldTy = try resolveValueType(self, typeNode);
5656
        try ensureStorableType(self, typeNode, fieldTy);
5657
5658
        if let v = valueNode {
5659
            let _valTy = try checkAssignable(self, v, fieldTy);
5660
        }
5661
        // Get field name for labeled records.
5662
        let mut fieldName: ?*[u8] = nil;
5663
        if labeled {
5664
            let n = fieldNode
5665
                else panic "resolveRecordFields: labeled record field missing name";
5666
            set fieldName = try nodeName(self, n);
5667
        }
5668
        let fieldType = typeFor(self, typeNode)
5669
            else throw emitError(self, typeNode, ErrorKind::CannotInferType);
5670
5671
        // Ensure field type is fully resolved before computing layout.
5672
        try ensureTypeResolved(self, fieldType, typeNode);
5673
5674
        // Compute field offset by aligning to field's alignment.
5675
        let fieldLayout = getTypeLayout(fieldType);
5676
        set currentOffset = mem::alignUp(currentOffset, fieldLayout.alignment);
5677
5678
        result.append(RecordField { name: fieldName, fieldType, offset: currentOffset as i32 }, a);
5679
5680
        // Advance offset past this field.
5681
        set currentOffset += fieldLayout.size;
5682
5683
        // Track max alignment for record layout.
5684
        set maxAlignment = max(maxAlignment, fieldLayout.alignment);
5685
    }
5686
    // Compute cached layout.
5687
    let recordLayout = Layout {
5688
        size: mem::alignUp(currentOffset, maxAlignment),
5689
        alignment: maxAlignment
5690
    };
5691
    return RecordType {
5692
        fields: &result[..],
5693
        labeled,
5694
        layout: recordLayout,
5695
        declaredLinear: false,
5696
    };
5697
}
5698
5699
/// Resolve record field types for a named record declaration.
5700
fn resolveRecordBody(self: *mut Resolver, node: *ast::Node, decl: ast::RecordDecl)
5701
    throws (ResolveError)
5702
{
5703
    // Get the type symbol that was bound to this declaration node.
5704
    // If there's no symbol, it's because an earlier phase failed.
5705
    let sym = symbolFor(self, node)
5706
        else return;
5707
    let case SymbolData::Type(nominalTy) = sym.data
5708
        else panic "resolveRecordBody: unexpected type symbol data";
5709
5710
    // Skip if already resolved.
5711
    if let case NominalType::Record(_) = *nominalTy {
5712
        return;
5713
    }
5714
    let declaredLinear = try resolveLinearDerive(self, decl.derives);
5715
    let mut recordType = try resolveRecordFields(self, node, decl.fields, decl.labeled);
5716
    set recordType.declaredLinear = declaredLinear;
5717
5718
    set *nominalTy = NominalType::Record(recordType);
5719
}
5720
5721
/// Bind a type name.
5722
fn bindTypeName(self: *mut Resolver, node: *ast::Node, name: *ast::Node, attrs: ?ast::Attributes) -> *mut Symbol
5723
    throws (ResolveError)
5724
{
5725
    let attrMask = resolveAttributes(self, attrs);
5726
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
5727
5728
    // Create a placeholder nominal type that will be replaced in
5729
    // the next phase.
5730
    let nominalTy = allocNominalType(self, NominalType::Placeholder(node));
5731
5732
    return try bindTypeIdent(self, name, node, nominalTy, attrMask);
5733
}
5734
5735
/// Allocate a trait type descriptor and return a pointer to it.
5736
fn allocTraitType(
5737
    self: *mut Resolver,
5738
    name: *[u8],
5739
    node: *ast::Node,
5740
) -> *mut TraitType {
5741
    let p = try! alloc::alloc(&mut self.arena, @sizeOf(TraitType), @alignOf(TraitType));
5742
    let entry = p as *mut TraitType;
5743
    let used = try! alloc::alloc(
5744
        &mut self.arena, @sizeOf(bool), @alignOf(bool)
5745
    ) as *mut bool;
5746
    set *used = false;
5747
    let selfType = try! alloc::alloc(
5748
        &mut self.arena, @sizeOf(GenericParamType), @alignOf(GenericParamType)
5749
    ) as *mut GenericParamType;
5750
    set *selfType = GenericParamType {
5751
        owner: node,
5752
        node,
5753
        name: "Self",
5754
        index: 0,
5755
        bounds: &[],
5756
        used,
5757
        constType: nil,
5758
    };
5759
    set *entry = TraitType {
5760
        name,
5761
        moduleId: self.currentMod,
5762
        nodeId: node.id,
5763
        methods: &mut [],
5764
        supertraits: &mut [],
5765
        selfType,
5766
        state: TraitState::Queued,
5767
        objectSafe: true,
5768
    };
5769
    return entry;
5770
}
5771
5772
/// Bind a trait name in the current scope.
5773
fn bindTraitName(
5774
    self: *mut Resolver,
5775
    node: *ast::Node,
5776
    name: *ast::Node,
5777
    attrs: ?ast::Attributes,
5778
) -> *mut Symbol throws (ResolveError) {
5779
    let attrMask = resolveAttributes(self, attrs);
5780
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
5781
    let traitName = try nodeName(self, name);
5782
    let traitType = allocTraitType(self, traitName, node);
5783
    let data = SymbolData::Trait(traitType);
5784
    let sym = try bindIdent(self, traitName, node, data, attrMask, self.scope);
5785
    setNodeType(self, node, Type::Void);
5786
    setNodeType(self, name, Type::Void);
5787
    return sym;
5788
}
5789
5790
/// Find a trait method by name.
5791
export fn findTraitMethod(traitType: *TraitType, name: *[u8]) -> ?*TraitMethod {
5792
    for i in 0..traitType.methods.len {
5793
        if traitType.methods[i].name == name {
5794
            return &traitType.methods[i];
5795
        }
5796
    }
5797
    return nil;
5798
}
5799
5800
/// Resolve one trait signature type with the declaring trait's rigid `Self`.
5801
fn resolveTraitSignatureType(
5802
    self: *mut Resolver,
5803
    traitType: *TraitType,
5804
    node: *ast::Node,
5805
) -> Type throws (ResolveError) {
5806
    let previous = self.currentTraitSelf;
5807
    set self.currentTraitSelf = traitType.selfType;
5808
    let resolved = try resolveValueType(self, node) catch {
5809
        set self.currentTraitSelf = previous;
5810
        throw ResolveError::Failure;
5811
    };
5812
    set self.currentTraitSelf = previous;
5813
    return resolved;
5814
}
5815
5816
/// Resolve a trait declaration body: supertrait methods, then own methods.
5817
fn resolveTraitBody(self: *mut Resolver, node: *ast::Node, supertraits: *mut [*ast::Node], methods: *mut [*ast::Node])
5818
    throws (ResolveError)
5819
{
5820
    let sym = symbolFor(self, node)
5821
        else return;
5822
    let case SymbolData::Trait(traitType) = sym.data
5823
        else return;
5824
    match traitType.state {
5825
        case TraitState::Complete, TraitState::Resolving => return,
5826
        case TraitState::Queued => set traitType.state = TraitState::Resolving,
5827
    }
5828
5829
    // Resolve supertrait bounds and copy their methods into this trait.
5830
    for superNode in supertraits {
5831
        let superSym = try resolveNamePath(self, superNode);
5832
        let case SymbolData::Trait(superTrait) = superSym.data
5833
            else throw emitError(self, superNode, ErrorKind::Internal);
5834
        // Resolve queued supertraits before consuming their method tables.
5835
        match superTrait.state {
5836
            case TraitState::Queued => {
5837
                let case ast::NodeValue::TraitDecl {
5838
                    supertraits: inheritedTraits, methods: inheritedMethods, ..
5839
                } = superSym.node.value
5840
                    else throw emitError(self, superNode, ErrorKind::Internal);
5841
                try resolveTraitBody(
5842
                    self, superSym.node, inheritedTraits, inheritedMethods
5843
                );
5844
            }
5845
            case TraitState::Resolving => {
5846
                throw emitError(self, superNode, ErrorKind::TraitInheritanceCycle);
5847
            }
5848
            case TraitState::Complete => {}
5849
        }
5850
5851
        setNodeSymbol(self, superNode, superSym);
5852
5853
        let a = alloc::arenaAllocator(&mut self.arena);
5854
        if traitType.methods.len + superTrait.methods.len > ast::MAX_TRAIT_METHODS {
5855
            throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
5856
                expected: ast::MAX_TRAIT_METHODS,
5857
                actual: traitType.methods.len as u32 + superTrait.methods.len as u32,
5858
            }));
5859
        }
5860
        // Copy inherited methods into this trait's method table.
5861
        for inherited in superTrait.methods {
5862
            if let _ = findTraitMethod(traitType, inherited.name) {
5863
                throw emitError(self, superNode, ErrorKind::DuplicateBinding(inherited.name));
5864
            }
5865
            traitType.methods.append(TraitMethod {
5866
                name: inherited.name,
5867
                fnType: inherited.fnType,
5868
                mutable: inherited.mutable,
5869
                receiverClass: inherited.receiverClass,
5870
                owner: inherited.owner,
5871
                index: traitType.methods.len as u32,
5872
            }, a);
5873
        }
5874
        traitType.supertraits.append(superTrait, a);
5875
        if not superTrait.objectSafe {
5876
            set traitType.objectSafe = false;
5877
        }
5878
    }
5879
5880
    if traitType.methods.len + methods.len > ast::MAX_TRAIT_METHODS {
5881
        throw emitError(self, node, ErrorKind::TraitMethodOverflow(CountMismatch {
5882
            expected: ast::MAX_TRAIT_METHODS,
5883
            actual: traitType.methods.len as u32 + methods.len as u32,
5884
        }));
5885
    }
5886
5887
    for methodNode in methods {
5888
        let case ast::NodeValue::TraitMethodSig { name, receiver, sig, attrs } = methodNode.value
5889
            else continue;
5890
        let methodName = try nodeName(self, name);
5891
        let attrMask = resolveAttributes(self, attrs);
5892
5893
        // Reject duplicate method names.
5894
        if let _ = findTraitMethod(traitType, methodName) {
5895
            throw emitError(self, name, ErrorKind::DuplicateBinding(methodName));
5896
        }
5897
        // Determine the receiver class and mutability, and validate that it
5898
        // points to the declaring trait.
5899
        let case ast::NodeValue::TypeSig(typeSig) = receiver.value
5900
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
5901
        let case ast::TypeSig::Pointer {
5902
            class: receiverClass, valueType: receiverValueType, mutable,
5903
        } = typeSig
5904
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
5905
        let case ast::NodeValue::TypeSig(innerSig) = receiverValueType.value
5906
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
5907
        let case ast::TypeSig::Nominal(nameNode) = innerSig
5908
            else throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
5909
        let receiverTargetName = try nodeName(self, nameNode);
5910
5911
        if receiverTargetName <> traitType.name {
5912
            throw emitError(self, receiver, ErrorKind::TraitReceiverMismatch);
5913
        }
5914
        // Resolve parameter types and return type.
5915
        let a = alloc::arenaAllocator(&mut self.arena);
5916
        let mut paramTypes: *mut [*Type] = &mut [];
5917
        let mut throwList: *mut [*Type] = &mut [];
5918
        let mut retType = allocType(self, Type::Void);
5919
5920
        if sig.params.len > MAX_FN_PARAMS {
5921
            throw emitError(self, methodNode, ErrorKind::FnParamOverflow(CountMismatch {
5922
                expected: MAX_FN_PARAMS,
5923
                actual: sig.params.len,
5924
            }));
5925
        }
5926
        for paramNode in sig.params {
5927
            let case ast::NodeValue::FnParam(param) = paramNode.value
5928
                else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
5929
            let paramTy = try resolveTraitSignatureType(self, traitType, param.type);
5930
            paramTypes.append(allocType(self, paramTy), a);
5931
        }
5932
        if let ret = sig.returnType {
5933
            set retType = allocType(
5934
                self, try resolveTraitSignatureType(self, traitType, ret)
5935
            );
5936
        }
5937
        // Resolve throws list.
5938
        if sig.throwList.len > MAX_FN_THROWS {
5939
            throw emitError(self, methodNode, ErrorKind::FnThrowOverflow(CountMismatch {
5940
                expected: MAX_FN_THROWS,
5941
                actual: sig.throwList.len,
5942
            }));
5943
        }
5944
        for throwNode in sig.throwList {
5945
            let throwTy = try resolveTraitSignatureType(self, traitType, throwNode);
5946
            throwList.append(allocType(self, throwTy), a);
5947
        }
5948
        let fnType = FnType {
5949
            paramTypes: &paramTypes[..],
5950
            returnType: retType,
5951
            throwList: &throwList[..],
5952
            isUnsafe: ast::hasAttribute(attrMask, ast::Attribute::Unsafe),
5953
            localCount: 0,
5954
        };
5955
        if containsGenericParameter(Type::Fn(&fnType)) {
5956
            set traitType.objectSafe = false;
5957
        }
5958
        traitType.methods.append(TraitMethod {
5959
            name: methodName,
5960
            fnType: allocFnType(self, fnType),
5961
            mutable,
5962
            receiverClass,
5963
            owner: traitType,
5964
            index: traitType.methods.len as u32,
5965
        }, a);
5966
5967
        setNodeType(self, methodNode, Type::Void);
5968
    }
5969
    set traitType.state = TraitState::Complete;
5970
}
5971
5972
/// Resolve a name path node to a symbol.
5973
/// Used for trait and type references in instance declarations and trait objects.
5974
fn resolveNamePath(self: *mut Resolver, node: *ast::Node) -> *mut Symbol
5975
    throws (ResolveError)
5976
{
5977
    match node.value {
5978
        case ast::NodeValue::Ident(name) => {
5979
            let sym = findAnySymbol(self.scope, name)
5980
                else throw emitError(self, node, ErrorKind::UnresolvedSymbol(name));
5981
            return sym;
5982
        }
5983
        case ast::NodeValue::ScopeAccess(access) => {
5984
            return try resolveAccess(self, node, access, self.scope);
5985
        }
5986
        else => {
5987
            throw emitError(self, node, ErrorKind::ExpectedIdentifier);
5988
        }
5989
    }
5990
}
5991
5992
/// Resolve an instance declaration.
5993
/// Validates that the trait exists, the target type exists, and all methods
5994
/// match the trait's signatures.
5995
fn resolveInstanceDecl(
5996
    self: *mut Resolver,
5997
    node: *ast::Node,
5998
    traitName: *ast::Node,
5999
    targetType: *ast::Node,
6000
    methods: *mut [*ast::Node]
6001
) throws (ResolveError) {
6002
    // Look up the trait.
6003
    let traitSym = try resolveNamePath(self, traitName);
6004
    let case SymbolData::Trait(traitInfo) = traitSym.data
6005
        else throw emitError(self, traitName, ErrorKind::Internal);
6006
6007
    setNodeSymbol(self, traitName, traitSym);
6008
6009
    // Resolve a concrete target type, including built-in scalar types.
6010
    let concreteType = try resolveValueType(self, targetType);
6011
    if containsGenericParameter(concreteType) {
6012
        throw emitError(self, targetType, ErrorKind::InvalidInstanceTarget);
6013
    }
6014
    if let case Type::Nominal(nominalTy) = concreteType {
6015
        try ensureNominalResolved(self, nominalTy, targetType);
6016
    }
6017
    if let _ = findInstance(self, traitInfo, concreteType) {
6018
        throw emitError(self, node, ErrorKind::DuplicateInstance);
6019
    }
6020
6021
    // Build the instance entry.
6022
    if self.instancesLen >= MAX_INSTANCES {
6023
        throw emitError(self, node, ErrorKind::Internal);
6024
    }
6025
    let methodSlice = try! alloc::allocSlice(
6026
        &mut self.arena, @sizeOf(*mut Symbol), @alignOf(*mut Symbol), traitInfo.methods.len as u32
6027
    ) as *mut [*mut Symbol];
6028
    let mut entry = InstanceEntry {
6029
        traitType: traitInfo,
6030
        concreteType,
6031
        moduleId: self.currentMod,
6032
        methods: methodSlice,
6033
    };
6034
    // Track which trait methods are covered by the instance.
6035
    let mut covered: [bool; ast::MAX_TRAIT_METHODS] = [false; ast::MAX_TRAIT_METHODS];
6036
6037
    // Match each instance method to a trait method.
6038
    for methodNode in methods {
6039
        let case ast::NodeValue::MethodDecl {
6040
            name, receiverName, receiverType, sig, body, attrs,
6041
        } = methodNode.value else continue;
6042
6043
        let methodName = try nodeName(self, name);
6044
        let attrMask = resolveAttributes(self, attrs);
6045
6046
        // Find the matching trait method.
6047
        let tm = findTraitMethod(traitInfo, methodName)
6048
            else throw emitError(self, name, ErrorKind::UnresolvedSymbol(methodName));
6049
        if tm.owner <> traitInfo {
6050
            throw emitError(self, name, ErrorKind::InheritedTraitMethod(methodName));
6051
        }
6052
        let selfArg = allocType(self, concreteType);
6053
        let selfParams: [*GenericParamType; 1] = [tm.owner.selfType];
6054
        let selfArgs: [*Type; 1] = [selfArg];
6055
        let selfSub = Substitution {
6056
            params: &selfParams[..],
6057
            args: &selfArgs[..],
6058
        };
6059
        let concreteMethodType = try substituteType(
6060
            self, Type::Fn(tm.fnType), &selfSub, methodNode
6061
        );
6062
        let case Type::Fn(expectedFn) = concreteMethodType
6063
            else throw emitError(self, methodNode, ErrorKind::Internal);
6064
        let instanceUnsafe = ast::hasAttribute(attrMask, ast::Attribute::Unsafe);
6065
        if instanceUnsafe <> tm.fnType.isUnsafe {
6066
            throw emitError(self, methodNode, ErrorKind::TraitMethodSafetyMismatch);
6067
        }
6068
6069
        // Determine receiver mutability and validate receiver type.
6070
        // The receiver must be `*Type` or `*mut Type`.
6071
        let case ast::NodeValue::TypeSig(typeSig) = receiverType.value
6072
            else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
6073
        let case ast::TypeSig::Pointer {
6074
            class: receiverClass, valueType, mutable: receiverMut,
6075
        } = typeSig
6076
            else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
6077
        if receiverClass <> tm.receiverClass {
6078
            throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
6079
        }
6080
6081
        // Validate that the receiver type annotation matches the
6082
        // concrete type from the instance declaration.
6083
        let annotatedTy = try infer(self, valueType);
6084
        if not typesEqual(annotatedTy, concreteType) {
6085
            throw emitTypeMismatch(self, receiverType, TypeMismatch {
6086
                expected: concreteType,
6087
                actual: annotatedTy,
6088
            });
6089
        }
6090
6091
        // Check receiver mutability matches in both directions.
6092
        if tm.mutable and not receiverMut {
6093
            throw emitError(self, receiverType, ErrorKind::ImmutableBinding);
6094
        }
6095
        if receiverMut and not tm.mutable {
6096
            throw emitError(self, receiverType, ErrorKind::ReceiverMutabilityMismatch);
6097
        }
6098
6099
        // Build the function type for the instance method.
6100
        // The receiver becomes the first parameter.
6101
        let receiverPtrType = Type::Pointer(PointerType {
6102
            class: receiverClass,
6103
            target: allocType(self, concreteType),
6104
            mutable: receiverMut,
6105
        });
6106
6107
        // Validate that the instance method's signature matches the
6108
        // trait method's signature exactly (params, return type, throws).
6109
        if sig.params.len <> expectedFn.paramTypes.len {
6110
            throw emitError(self, methodNode, ErrorKind::FnArgCountMismatch(CountMismatch {
6111
                expected: expectedFn.paramTypes.len as u32,
6112
                actual: sig.params.len,
6113
            }));
6114
        }
6115
        for paramNode, j in sig.params {
6116
            let case ast::NodeValue::FnParam(param) = paramNode.value
6117
                else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
6118
            let instanceParamTy = try resolveValueType(self, param.type);
6119
            if not typesEqual(instanceParamTy, *expectedFn.paramTypes[j]) {
6120
                throw emitTypeMismatch(self, paramNode, TypeMismatch {
6121
                    expected: *expectedFn.paramTypes[j],
6122
                    actual: instanceParamTy,
6123
                });
6124
            }
6125
        }
6126
        let mut instanceRetTy = Type::Void;
6127
        if let retNode = sig.returnType {
6128
            set instanceRetTy = try resolveValueType(self, retNode);
6129
        }
6130
        if not typesEqual(instanceRetTy, *expectedFn.returnType) {
6131
            throw emitTypeMismatch(self, methodNode, TypeMismatch {
6132
                expected: *expectedFn.returnType,
6133
                actual: instanceRetTy,
6134
            });
6135
        }
6136
        if sig.throwList.len <> expectedFn.throwList.len {
6137
            throw emitError(self, methodNode, ErrorKind::FnThrowCountMismatch(CountMismatch {
6138
                expected: expectedFn.throwList.len as u32,
6139
                actual: sig.throwList.len,
6140
            }));
6141
        }
6142
        for throwNode, j in sig.throwList {
6143
            let instanceThrowTy = try resolveValueType(self, throwNode);
6144
            if not typesEqual(instanceThrowTy, *expectedFn.throwList[j]) {
6145
                throw emitTypeMismatch(self, throwNode, TypeMismatch {
6146
                    expected: *expectedFn.throwList[j],
6147
                    actual: instanceThrowTy,
6148
                });
6149
            }
6150
        }
6151
6152
        // Build final function type: receiver plus trait's canonical types.
6153
        let a = alloc::arenaAllocator(&mut self.arena);
6154
        // TODO: Improve this pattern, maybe via something like `(&[]).append(..)`?
6155
        let mut paramTypes: *mut [*Type] = &mut [];
6156
        paramTypes.append(allocType(self, receiverPtrType), a);
6157
6158
        for ty in expectedFn.paramTypes {
6159
            paramTypes.append(ty, a);
6160
        }
6161
        let fnType = FnType {
6162
            paramTypes: &paramTypes[..],
6163
            returnType: expectedFn.returnType,
6164
            throwList: expectedFn.throwList,
6165
            isUnsafe: expectedFn.isUnsafe,
6166
            localCount: 0,
6167
        };
6168
6169
        // Create a symbol for the instance method without binding it into the
6170
        // module scope. Instance methods are dispatched via v-table, so they
6171
        // must not pollute the enclosing scope.
6172
        let fnTy = Type::Fn(allocFnType(self, fnType));
6173
        let mName = try nodeName(self, name);
6174
        let sym = allocSymbol(self, SymbolData::Value {
6175
            mutable: false, alignment: 0, type: fnTy, addressTaken: false,
6176
        }, mName, methodNode, attrMask);
6177
6178
        setNodeSymbol(self, methodNode, sym);
6179
        setNodeType(self, methodNode, fnTy);
6180
        setNodeType(self, name, fnTy);
6181
6182
        // Store in instance entry at the matching v-table slot.
6183
        set entry.methods[tm.index] = sym;
6184
        set covered[tm.index] = true;
6185
    }
6186
6187
    // Fill inherited method slots from supertrait instances.
6188
    for superTrait in traitInfo.supertraits {
6189
        let superInst = findInstance(self, superTrait, concreteType)
6190
            else throw emitError(self, node, ErrorKind::MissingSupertraitInstance(superTrait.name));
6191
        for superMethod, mi in superTrait.methods {
6192
            let merged = findTraitMethod(traitInfo, superMethod.name)
6193
                else panic "resolveInstanceDecl: inherited method not found";
6194
            if not covered[merged.index] {
6195
                set entry.methods[merged.index] = superInst.methods[mi];
6196
                set covered[merged.index] = true;
6197
            }
6198
        }
6199
    }
6200
6201
    // Check that all trait methods are implemented.
6202
    for method, i in traitInfo.methods {
6203
        if not covered[i] {
6204
            throw emitError(self, node, ErrorKind::MissingTraitMethod(method.name));
6205
        }
6206
    }
6207
    set self.instances[self.instancesLen] = entry;
6208
    set self.instancesLen += 1;
6209
6210
    setNodeType(self, node, Type::Void);
6211
}
6212
6213
/// Resolve instance method bodies.
6214
fn resolveInstanceMethodBodies(self: *mut Resolver, methods: *mut [*ast::Node])
6215
    throws (ResolveError)
6216
{
6217
    for methodNode in methods {
6218
        let case ast::NodeValue::MethodDecl {
6219
            name, receiverName, receiverType, sig, body, ..
6220
        } = methodNode.value else continue;
6221
6222
        // Symbol may be absent if [`resolveInstanceDecl`] reported an error
6223
        // for this method (eg. unknown method name). Skip gracefully.
6224
        let sym = symbolFor(self, methodNode)
6225
            else continue;
6226
6227
        try resolveMethodBody(self, methodNode, receiverName, sig, body);
6228
    }
6229
}
6230
6231
/// Resolve a method body shared by instance methods and standalone methods.
6232
/// Binds the receiver and parameters, then type-checks the body.
6233
fn resolveMethodBody(
6234
    self: *mut Resolver,
6235
    node: *ast::Node,
6236
    receiverName: *ast::Node,
6237
    sig: ast::FnSig,
6238
    body: *ast::Node,
6239
) throws (ResolveError) {
6240
    let sym = symbolFor(self, node)
6241
        else throw emitError(self, node, ErrorKind::Internal);
6242
    let case SymbolData::Value { type: Type::Fn(fnType), .. } = sym.data
6243
        else panic "resolveMethodBody: expected value symbol";
6244
    let isUnsafe = fnType.isUnsafe;
6245
    if isUnsafe {
6246
        set self.unsafeDepth += 1;
6247
    }
6248
6249
    // Enter function scope.
6250
    enterFn(self, node, fnType);
6251
6252
    // Bind the receiver parameter.
6253
    let receiverTy = *fnType.paramTypes[0];
6254
    try bindValueIdent(self, receiverName, receiverName, receiverTy, false, 0, 0) catch e {
6255
        exitFn(self);
6256
        if isUnsafe { set self.unsafeDepth -= 1; }
6257
        throw e;
6258
    };
6259
    // Bind the remaining parameters from the signature.
6260
    for paramNode in sig.params {
6261
        let paramTy = try infer(self, paramNode) catch e {
6262
            exitFn(self);
6263
            if isUnsafe { set self.unsafeDepth -= 1; }
6264
            throw e;
6265
        };
6266
    }
6267
6268
    // Resolve the body.
6269
    let retTy = *fnType.returnType;
6270
    let bodyTy = try checkAssignable(self, body, Type::Void) catch e {
6271
        exitFn(self);
6272
        if isUnsafe { set self.unsafeDepth -= 1; }
6273
        throw e;
6274
    };
6275
    if retTy <> Type::Void and bodyTy <> Type::Never {
6276
        exitFn(self);
6277
        if isUnsafe { set self.unsafeDepth -= 1; }
6278
        throw emitError(self, body, ErrorKind::FnMissingReturn);
6279
    }
6280
    exitFn(self);
6281
    if isUnsafe {
6282
        set self.unsafeDepth -= 1;
6283
    }
6284
    if self.linearEnabled {
6285
        try checkLinearFn(self, receiverName, sig.params, body);
6286
    }
6287
}
6288
6289
/// Resolve a standalone method declaration (signature only).
6290
/// Validates the receiver type and registers the method in the method table.
6291
6292
/// Resolve and register a standalone method declaration.
6293
fn resolveMethodDecl(
6294
    self: *mut Resolver,
6295
    node: *ast::Node,
6296
    name: *ast::Node,
6297
    receiverName: *ast::Node,
6298
    receiverType: *ast::Node,
6299
    sig: ast::FnSig,
6300
    attrs: ?ast::Attributes,
6301
) throws (ResolveError) {
6302
    // Resolve the receiver type: must be `*Type` or `*mut Type` pointing to a
6303
    // nominal type.
6304
    let fullReceiverTy = try infer(self, receiverType);
6305
    let case Type::Pointer(receiver) = fullReceiverTy
6306
        else throw emitError(self, receiverType, ErrorKind::TraitReceiverMismatch);
6307
    let concreteType = *receiver.target;
6308
    let case Type::Nominal(nominalTy) = concreteType
6309
        else throw emitError(self, receiverType, ErrorKind::ExpectedRecord);
6310
    try ensureNominalResolved(self, nominalTy, receiverType);
6311
6312
    let methodName = try nodeName(self, name);
6313
    let attrMask = resolveAttributes(self, attrs);
6314
6315
    // Reject duplicate method for the same (type, name).
6316
    if let _ = findMethod(self, concreteType, methodName) {
6317
        throw emitError(self, name, ErrorKind::DuplicateBinding(methodName));
6318
    }
6319
6320
    // Resolve parameter types.
6321
    let a = alloc::arenaAllocator(&mut self.arena);
6322
    let mut paramTypes: *mut [*Type] = &mut [];
6323
6324
    // Receiver is the first parameter.
6325
    let receiverPtrType = Type::Pointer(PointerType {
6326
        class: receiver.class,
6327
        target: allocType(self, concreteType),
6328
        mutable: receiver.mutable,
6329
    });
6330
    paramTypes.append(allocType(self, receiverPtrType), a);
6331
6332
    for paramNode in sig.params {
6333
        let case ast::NodeValue::FnParam(param) = paramNode.value
6334
            else throw emitError(self, paramNode, ErrorKind::ExpectedIdentifier);
6335
        let paramTy = try resolveValueType(self, param.type);
6336
        paramTypes.append(allocType(self, paramTy), a);
6337
    }
6338
6339
    // Resolve return type.
6340
    let mut returnType = Type::Void;
6341
    if let retNode = sig.returnType {
6342
        set returnType = try resolveValueType(self, retNode);
6343
    }
6344
6345
    // Resolve throw list.
6346
    let mut throwTypes: *mut [*Type] = &mut [];
6347
    for throwNode in sig.throwList {
6348
        let throwTy = try resolveValueType(self, throwNode);
6349
        throwTypes.append(allocType(self, throwTy), a);
6350
    }
6351
6352
    let retTypePtr = allocType(self, returnType);
6353
    let throwList = &throwTypes[..];
6354
6355
    let isUnsafe = ast::hasAttribute(attrMask, ast::Attribute::Unsafe);
6356
    // Full function type (receiver + params) for lowering.
6357
    let fullFnType = FnType {
6358
        paramTypes: &paramTypes[..],
6359
        returnType: retTypePtr,
6360
        throwList,
6361
        isUnsafe,
6362
        localCount: 0,
6363
    };
6364
    let fnTy = Type::Fn(allocFnType(self, fullFnType));
6365
6366
    // Function type excluding receiver, for call arg checking.
6367
    let checkFnType = FnType {
6368
        paramTypes: &paramTypes[1..],
6369
        returnType: retTypePtr,
6370
        throwList,
6371
        isUnsafe,
6372
        localCount: 0,
6373
    };
6374
6375
    // Create a symbol for the method without binding it into the module scope.
6376
    let sym = allocSymbol(self, SymbolData::Value {
6377
        mutable: false, alignment: 0, type: fnTy, addressTaken: false,
6378
    }, methodName, node, attrMask);
6379
6380
    setNodeSymbol(self, node, sym);
6381
    setNodeType(self, node, fnTy);
6382
    setNodeType(self, name, fnTy);
6383
6384
    // Register in the method table.
6385
    if self.methodsLen >= MAX_METHODS {
6386
        throw emitError(self, node, ErrorKind::Internal);
6387
    }
6388
    set self.methods[self.methodsLen] = MethodEntry {
6389
        concreteType,
6390
        name: methodName,
6391
        fnType: allocFnType(self, checkFnType),
6392
        mutable: receiver.mutable,
6393
        receiverClass: receiver.class,
6394
        symbol: sym,
6395
    };
6396
    set self.methodsLen += 1;
6397
}
6398
6399
/// Look up an instance entry by trait and concrete type.
6400
export fn findInstance(self: *Resolver, traitInfo: *TraitType, concreteType: Type) -> ?*InstanceEntry {
6401
    for i in 0..self.instancesLen {
6402
        let entry = &self.instances[i];
6403
        if entry.traitType == traitInfo and typesEqual(entry.concreteType, concreteType) {
6404
            return entry;
6405
        }
6406
    }
6407
    return nil;
6408
}
6409
6410
/// Look up a standalone method by concrete type and name.
6411
export fn findMethod(self: *Resolver, concreteType: Type, name: *[u8]) -> ?*MethodEntry {
6412
    for i in 0..self.methodsLen {
6413
        let entry = &self.methods[i];
6414
        if typesEqual(entry.concreteType, concreteType) and entry.name == name {
6415
            return entry;
6416
        }
6417
    }
6418
    return nil;
6419
}
6420
6421
/// Look up a standalone method entry by its symbol.
6422
export fn findMethodBySymbol(self: *Resolver, sym: *mut Symbol) -> ?*MethodEntry {
6423
    for i in 0..self.methodsLen {
6424
        let entry = &self.methods[i];
6425
        if entry.symbol == sym {
6426
            return entry;
6427
        }
6428
    }
6429
    return nil;
6430
}
6431
6432
/// Resolve union variant types after all type names are bound (Phase 2 of type resolution).
6433
fn resolveUnionBody(self: *mut Resolver, node: *ast::Node, decl: ast::UnionDecl)
6434
    throws (ResolveError)
6435
{
6436
    // Get the type symbol that was bound to this declaration node.
6437
    // If there's no symbol, it's because an earlier phase failed.
6438
    let sym = symbolFor(self, node)
6439
        else return;
6440
    let case SymbolData::Type(nominalTy) = sym.data
6441
        else panic "resolveUnionBody: unexpected symbol data";
6442
6443
    // Check if already resolved, in which case there's no need to
6444
    // do it again.
6445
    if let case NominalType::Union(_) = *nominalTy {
6446
        return;
6447
    }
6448
    let a = alloc::arenaAllocator(&mut self.arena);
6449
    let mut variants: *mut [UnionVariant] = &mut [];
6450
6451
    // Create a temporary nominal type to replace the placeholder.This prevents infinite recursion
6452
    // when a variant references this union type (e.g. record payloads with `*[Self]`).
6453
    // TODO: It would be best to have a resolving state eg. `Visiting` for this situation.
6454
    let declaredLinear = try resolveLinearDerive(self, decl.derives);
6455
    set *nominalTy = NominalType::Union(UnionType {
6456
        variants: &[],
6457
        layout: Layout { size: 0, alignment: 0 },
6458
        valOffset: 0,
6459
        isAllVoid: true,
6460
        declaredLinear,
6461
    });
6462
6463
    assert decl.variants.len <= MAX_UNION_VARIANTS, "resolveUnionBody: maximum union variants exceeded";
6464
    let mut iota: u32 = 0;
6465
    for variantNode, i in decl.variants {
6466
        let case ast::NodeValue::UnionDeclVariant(variantDecl) = variantNode.value
6467
            else panic "resolveUnionBody: invalid union variant";
6468
        let variantName = try nodeName(self, variantDecl.name);
6469
        // Resolve the variant's payload type if present.
6470
        let mut variantType = Type::Void;
6471
        if let typeNode = variantDecl.type {
6472
            set variantType = try infer(self, typeNode);
6473
            try ensureStorableType(self, typeNode, variantType);
6474
        }
6475
        // Process the variant's explicit discriminant value if present.
6476
        if let value = variantDecl.value {
6477
            let _ = try checkSizeInt(self, value);
6478
        }
6479
        let tag = try variantTag(self, variantDecl, &mut iota, nil);
6480
        // Create a symbol for this variant.
6481
        let data = SymbolData::Variant { type: variantType, decl: node, ordinal: i, index: tag };
6482
        let variantSym = allocSymbol(self, data, variantName, variantNode, 0);
6483
6484
        variants.append(UnionVariant {
6485
            name: variantName,
6486
            valueType: variantType,
6487
            symbol: variantSym,
6488
        }, a);
6489
    }
6490
    let info = computeUnionLayout(&variants[..]);
6491
6492
    // Update the nominal type with the resolved variants.
6493
    set *nominalTy = NominalType::Union(UnionType {
6494
        variants: &variants[..],
6495
        layout: info.layout,
6496
        valOffset: info.valOffset,
6497
        isAllVoid: info.isAllVoid,
6498
        declaredLinear,
6499
    });
6500
}
6501
6502
/// Check if a module should be analyzed based on its attributes and build configuration.
6503
fn shouldAnalyzeModule(self: *Resolver, attrs: ?ast::Attributes) -> bool {
6504
    if let attributes = attrs {
6505
        // Skip test modules unless we're building in test mode.
6506
        if ast::attributesContains(&attributes, ast::Attribute::Test) and not self.config.buildTest {
6507
            return false;
6508
        }
6509
    }
6510
    return true;
6511
}
6512
6513
/// Analyze a module during the graph analysis phase.
6514
fn resolveModGraph(self: *mut Resolver, node: *ast::Node, decl: ast::Mod)
6515
    throws (ResolveError)
6516
{
6517
    if not shouldAnalyzeModule(self, decl.attrs) {
6518
        return;
6519
    }
6520
    let modName = try nodeName(self, decl.name);
6521
    let attrMask = resolveAttributes(self, decl.attrs);
6522
    try ensureDefaultAttrNotAllowed(self, node, attrMask);
6523
    let submod = try enterSubModule(self, modName, node);
6524
6525
    // Bind the module symbol in the outer scope, ie. where the `mod` statement is.
6526
    try bindModuleIdent(self, submod.entry, submod.newScope, submod.root, attrMask, submod.prevScope);
6527
    let case ast::NodeValue::Block(block) = submod.root.value
6528
        else panic "resolveModGraph: expected block for module root";
6529
    try resolveModuleGraph(self, &block);
6530
6531
    exitModuleScope(self, submod);
6532
}
6533
6534
/// Analyze a module in the declaration phase.
6535
fn resolveModDecl(self: *mut Resolver, node: *ast::Node, decl: ast::Mod)
6536
    throws (ResolveError)
6537
{
6538
    if not shouldAnalyzeModule(self, decl.attrs) {
6539
        return;
6540
    }
6541
    // Find module under the current module.
6542
    let modName = try nodeName(self, decl.name);
6543
    let submod = try enterSubModule(self, modName, node);
6544
    let case ast::NodeValue::Block(block) = submod.root.value
6545
        else panic "resolveModDecl: expected block for module root";
6546
    try resolveModuleDecls(self, &block);
6547
6548
    exitModuleScope(self, submod);
6549
}
6550
6551
/// Analyze a `use` statement and create a symbol for the imported module.
6552
fn resolveUse(self: *mut Resolver, node: *ast::Node, decl: ast::Use) -> Type
6553
    throws (ResolveError)
6554
{
6555
    let resolved = try resolveModulePath(self, decl.path);
6556
    let attrMask = resolveAttributes(self, decl.attrs);
6557
6558
    if decl.wildcard {
6559
        // Import all public symbols from the target module.
6560
        for i in 0..resolved.scope.symbolsLen {
6561
            let sym = resolved.scope.symbols[i];
6562
            if ast::hasAttribute(sym.attrs, ast::Attribute::Export) {
6563
                if let existing = findSymbolInScope(self.scope, sym.name) {
6564
                    if existing == sym {
6565
                        continue;
6566
                    }
6567
                }
6568
                try addSymbolToScope(self, sym, self.scope, node);
6569
            }
6570
        }
6571
    } else {
6572
        // Regular module import.
6573
        try bindModuleIdent(self, resolved.entry, resolved.scope, node, attrMask, self.scope);
6574
    }
6575
    return Type::Void;
6576
}
6577
6578
/// Analyze a standard `if` statement.
6579
fn resolveIf(self: *mut Resolver, node: *ast::Node, cond: ast::If) -> Type
6580
    throws (ResolveError)
6581
{
6582
    try checkBoolean(self, cond.condition);
6583
    let thenTy = try visit(self, cond.thenBranch, Type::Void);
6584
    let elseTy = try visitOptional(self, cond.elseBranch, Type::Void);
6585
6586
    return setNodeType(self, node, unifyBranches(thenTy, elseTy));
6587
}
6588
6589
/// Analyze a conditional expression.
6590
fn resolveCondExpr(self: *mut Resolver, node: *ast::Node, cond: ast::CondExpr) -> Type
6591
    throws (ResolveError)
6592
{
6593
    try checkBoolean(self, cond.condition);
6594
    let thenTy = try infer(self, cond.thenExpr);
6595
    let elseTy = try infer(self, cond.elseExpr);
6596
6597
    // Either branch may supply the concrete type for an otherwise context-
6598
    // dependent expression, such as an unsuffixed integer or `nil`.
6599
    if let coercion = isAssignable(self, thenTy, elseTy, cond.elseExpr) {
6600
        setNodeCoercion(self, cond.elseExpr, coercion);
6601
        return setNodeType(self, node, thenTy);
6602
    }
6603
    if let coercion = isAssignable(self, elseTy, thenTy, cond.thenExpr) {
6604
        setNodeCoercion(self, cond.thenExpr, coercion);
6605
        return setNodeType(self, node, elseTy);
6606
    }
6607
    try expectAssignable(self, thenTy, elseTy, cond.elseExpr);
6608
6609
    return setNodeType(self, node, thenTy);
6610
}
6611
6612
/// Analyze a pattern match structure (used by if-let, while-let).
6613
fn resolvePatternMatch(self: *mut Resolver, node: *ast::Node, pat: *ast::PatternMatch)
6614
    throws (ResolveError)
6615
{
6616
    match pat.kind {
6617
        case ast::PatternKind::Case => {
6618
            // Analyze pattern against scrutinee type.
6619
            let scrutineeTy = try infer(self, pat.scrutinee);
6620
            let subject = unwrapMatchSubject(scrutineeTy);
6621
            try resolveCasePattern(self, pat.pattern, subject.effectiveTy, IdentMode::Compare, subject.by);
6622
        }
6623
        case ast::PatternKind::Binding => {
6624
            // Scrutinee must be optional, bind the payload.
6625
            let scrutineeTy = try checkOptional(self, pat.scrutinee);
6626
            let payloadTy = *scrutineeTy;
6627
6628
            try bindValueIdent(self, pat.pattern, node, payloadTy, pat.mutable, 0, 0);
6629
            setNodeType(self, pat.pattern, payloadTy);
6630
        }
6631
    }
6632
    if let guard = pat.guard {
6633
        try checkBoolean(self, guard);
6634
    }
6635
}
6636
6637
/// Analyze an `if let` or `if let case` pattern binding.
6638
fn resolveIfLet(self: *mut Resolver, node: *ast::Node, cond: ast::IfLet) -> Type
6639
    throws (ResolveError)
6640
{
6641
    enterScope(self, node);
6642
    try resolvePatternMatch(self, node, &cond.pattern);
6643
6644
    let thenTy = try visit(self, cond.thenBranch, Type::Void);
6645
    exitScope(self);
6646
6647
    let elseTy = try visitOptional(self, cond.elseBranch, Type::Void);
6648
6649
    return setNodeType(self, node, unifyBranches(thenTy, elseTy));
6650
}
6651
6652
/// Controls how bare identifiers are handled in case patterns.
6653
union IdentMode {
6654
    /// Identifier is a value to compare against.
6655
    Compare,
6656
    /// Identifier introduces a new binding.
6657
    Bind,
6658
}
6659
6660
/// Check whether a pattern node is a destructuring pattern that looks
6661
/// through structure (union variant, record literal, scope access).
6662
/// Identifiers, placeholders, and plain literals are not destructuring.
6663
export fn isDestructuringPattern(pattern: *ast::Node) -> bool {
6664
    match pattern.value {
6665
        case ast::NodeValue::Call(_),
6666
             ast::NodeValue::RecordLit(_),
6667
             ast::NodeValue::ScopeAccess(_) => return true,
6668
        else => return false,
6669
    }
6670
}
6671
6672
/// Analyze a case pattern for match, if-case, let-case, or while-case.
6673
///
6674
/// At the top level, bare identifiers are compared against existing values.
6675
/// Inside destructuring patterns (arrays, records), identifiers become bindings.
6676
fn resolveCasePattern(
6677
    self: *mut Resolver,
6678
    pattern: *ast::Node,
6679
    scrutineeTy: Type,
6680
    mode: IdentMode,
6681
    matchBy: MatchBy
6682
) throws (ResolveError) {
6683
    if let case Type::Pointer(pointer) = scrutineeTy; isDestructuringPattern(pattern) {
6684
        try resolveCasePattern(self, pattern, *pointer.target, mode, matchBy);
6685
        return;
6686
    }
6687
    // TODO: Collapse these nested matches.
6688
    match scrutineeTy {
6689
        case Type::Nominal(info) => {
6690
            try ensureNominalResolved(self, info, pattern);
6691
6692
            match *info {
6693
                case NominalType::Union(unionType) => {
6694
                    try resolveUnionPattern(self, pattern, scrutineeTy, unionType, matchBy);
6695
                    return;
6696
                }
6697
                case NominalType::Record(recInfo) => {
6698
                    match pattern.value {
6699
                        case ast::NodeValue::Call(_), ast::NodeValue::RecordLit(_) => {
6700
                            try bindRecordPatternFields(self, pattern, recInfo, matchBy);
6701
                            return;
6702
                        } else => {}
6703
                    }
6704
                } else => {}
6705
            }
6706
        }
6707
        case Type::Array(arrayInfo) => {
6708
            if let case ast::NodeValue::ArrayLit(items) = pattern.value {
6709
                if items.len as u32 <> arrayInfo.length {
6710
                    throw emitError(self, pattern, ErrorKind::RecordFieldCountMismatch(
6711
                        CountMismatch { expected: arrayInfo.length, actual: items.len as u32 }
6712
                    ));
6713
                }
6714
                let elemTy = *arrayInfo.item;
6715
                for item in items {
6716
                    try resolveCasePattern(self, item, elemTy, IdentMode::Bind, matchBy);
6717
                }
6718
                setNodeType(self, pattern, scrutineeTy);
6719
                return;
6720
            }
6721
        } else => {}
6722
    }
6723
    // Handle non-binding patterns (literals, placeholders) and bindings.
6724
    match pattern.value {
6725
        case ast::NodeValue::Placeholder => {
6726
            // Placeholder matches without introducing bindings.
6727
        }
6728
        case ast::NodeValue::Ident(_) => {
6729
            match mode {
6730
                case IdentMode::Bind => try bindPatternVar(self, pattern, scrutineeTy, matchBy),
6731
                case IdentMode::Compare => try checkAssignable(self, pattern, scrutineeTy),
6732
            }
6733
        }
6734
        else => {
6735
            // Literals and other expressions: check type compatibility.
6736
            try checkAssignable(self, pattern, scrutineeTy);
6737
        }
6738
    }
6739
}
6740
6741
/// Analyze a traditional `while` loop.
6742
fn resolveWhile(self: *mut Resolver, node: *ast::Node, loopNode: ast::While) -> Type
6743
    throws (ResolveError)
6744
{
6745
    try checkBoolean(self, loopNode.condition);
6746
    try visitLoop(self, loopNode.body);
6747
    try visitOptional(self, loopNode.elseBranch, Type::Void);
6748
6749
    return setNodeType(self, node, Type::Void);
6750
}
6751
6752
/// Analyze a `while let` loop with pattern binding.
6753
fn resolveWhileLet(self: *mut Resolver, node: *ast::Node, loopNode: ast::WhileLet) -> Type
6754
    throws (ResolveError)
6755
{
6756
    enterScope(self, node);
6757
    try resolvePatternMatch(self, node, &loopNode.pattern);
6758
6759
    try visitLoop(self, loopNode.body);
6760
    exitScope(self);
6761
6762
    try visitOptional(self, loopNode.elseBranch, Type::Void);
6763
6764
    return setNodeType(self, node, Type::Void);
6765
}
6766
6767
/// Analyze a `for` loop, binding iteration variables.
6768
fn resolveFor(self: *mut Resolver, node: *ast::Node, forStmt: ast::For) -> Type
6769
    throws (ResolveError)
6770
{
6771
    let iterableTy = try infer(self, forStmt.iterable);
6772
6773
    // Extract binding names for the lowerer.
6774
    let mut bindingName: ?*[u8] = nil;
6775
    if let case ast::NodeValue::Ident(name) = forStmt.binding.value {
6776
        set bindingName = name;
6777
    }
6778
    let mut indexName: ?*[u8] = nil;
6779
    if let idx = forStmt.index {
6780
        if let case ast::NodeValue::Ident(name) = idx.value {
6781
            set indexName = name;
6782
        }
6783
    }
6784
    // Extract item type and store pre-computed loop metadata for the lowerer.
6785
    let mut itemTy: Type = undefined;
6786
    match iterableTy {
6787
        case Type::Slice(slice) => {
6788
            set itemTy = *slice.item;
6789
            setForLoopInfo(self, node, ForLoopInfo::Collection {
6790
                elemType: slice.item, length: nil, bindingName, indexName
6791
            });
6792
        }
6793
        case Type::Range { start, .. } => {
6794
            // Iterable ranges must have a start, and since we enforce type
6795
            // equality for start and end, that is always the item type.
6796
            let valType = start else {
6797
                throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable);
6798
            };
6799
            let case ast::NodeValue::Range(range) = forStmt.iterable.value else {
6800
                throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable);
6801
            };
6802
            set itemTy = *valType;
6803
6804
            setForLoopInfo(self, node, ForLoopInfo::Range {
6805
                valType, range, bindingName, indexName
6806
            });
6807
        }
6808
        case Type::Array(arrayInfo) => {
6809
            set itemTy = *arrayInfo.item;
6810
            setForLoopInfo(self, node, ForLoopInfo::Collection {
6811
                elemType: arrayInfo.item,
6812
                length: arrayInfo.length,
6813
                bindingName,
6814
                indexName,
6815
            });
6816
        }
6817
        else => throw emitError(self, forStmt.iterable, ErrorKind::ExpectedIterable),
6818
    }
6819
    enterScope(self, node);
6820
    try bindForLoopPattern(self, forStmt.binding, itemTy, false);
6821
6822
    if let pat = forStmt.index {
6823
        try bindForLoopPattern(self, pat, Type::U32, false);
6824
    }
6825
    // The lowerer always creates at least one internal variable for iteration,
6826
    // even when the binding is a placeholder or no explicit index is given.
6827
    if let mut fnType = self.currentFn {
6828
        set fnType.localCount += 1;
6829
    }
6830
    try visitLoop(self, forStmt.body);
6831
    exitScope(self);
6832
6833
    try visitOptional(self, forStmt.elseBranch, Type::Void);
6834
6835
    return setNodeType(self, node, Type::Void);
6836
}
6837
6838
/// Get the node within a pattern that carries the `UnionVariant` extra.
6839
/// For `ScopeAccess` it is the pattern itself, for `RecordLit` it is the
6840
/// type name, and for `Call` it is the callee.
6841
export fn patternVariantKeyNode(pattern: *ast::Node) -> ?*ast::Node {
6842
    match pattern.value {
6843
        case ast::NodeValue::ScopeAccess(_) => return pattern,
6844
        case ast::NodeValue::RecordLit(lit) => return lit.typeName,
6845
        case ast::NodeValue::Call(call) => return call.callee,
6846
        else => return nil,
6847
    }
6848
}
6849
6850
/// Get the i-th sub-pattern element from a compound pattern.
6851
/// For `RecordLit` this is the i-th field's value; for `Call` it is the
6852
/// i-th argument.
6853
fn patternSubElement(pattern: *ast::Node, idx: u32) -> ?*ast::Node {
6854
    match pattern.value {
6855
        case ast::NodeValue::RecordLit(lit) => {
6856
            if idx < lit.fields.len as u32 {
6857
                if let case ast::NodeValue::RecordLitField(field) = lit.fields[idx].value {
6858
                    return field.value;
6859
                }
6860
            }
6861
        }
6862
        case ast::NodeValue::Call(call) => {
6863
            if idx < call.args.len as u32 {
6864
                return call.args[idx];
6865
            }
6866
        }
6867
        else => {}
6868
    }
6869
    return nil;
6870
}
6871
6872
/// Get the number of sub-pattern elements in a compound pattern.
6873
fn patternSubCount(pattern: *ast::Node) -> u32 {
6874
    match pattern.value {
6875
        case ast::NodeValue::RecordLit(lit) => return lit.fields.len as u32,
6876
        case ast::NodeValue::Call(call) => return call.args.len as u32,
6877
        else => return 0,
6878
    }
6879
}
6880
6881
/// Check whether a pattern contains nested sub-patterns that further
6882
/// refine the match beyond the outer variant (e.g. nested union variant
6883
/// tests or literal comparisons). Used to allow the same outer variant
6884
/// to appear in multiple match arms.
6885
fn hasNestedRefiningPattern(self: *Resolver, pattern: *ast::Node) -> bool {
6886
    for i in 0..patternSubCount(pattern) {
6887
        if let sub = patternSubElement(pattern, i) {
6888
            if isRefiningPattern(self, sub) {
6889
                return true;
6890
            }
6891
        }
6892
    }
6893
    return false;
6894
}
6895
6896
/// Check whether a single pattern node is a refining pattern that tests
6897
/// a value rather than just binding it. Union variants, literals, and
6898
/// scope accesses are refining; identifiers, placeholders, and plain
6899
/// record destructurings are not.
6900
fn isRefiningPattern(self: *Resolver, pattern: *ast::Node) -> bool {
6901
    match pattern.value {
6902
        case ast::NodeValue::Ident(_), ast::NodeValue::Placeholder =>
6903
            return false,
6904
        case ast::NodeValue::RecordLit(_), ast::NodeValue::Call(_) => {
6905
            if let keyNode = patternVariantKeyNode(pattern) {
6906
                if let case NodeExtra::UnionVariant { .. } = self.nodeData.entries[keyNode.id].extra {
6907
                    return true;
6908
                }
6909
            }
6910
            // Plain record destructuring / non-variant call is not directly
6911
            // refining; recurse to check sub-patterns.
6912
            return hasNestedRefiningPattern(self, pattern);
6913
        }
6914
        case ast::NodeValue::ArrayLit(items) => {
6915
            for item in items {
6916
                if isRefiningPattern(self, item) {
6917
                    return true;
6918
                }
6919
            }
6920
            return false;
6921
        }
6922
        case ast::NodeValue::ScopeAccess(_) =>
6923
            return true,
6924
        else =>
6925
            return true,
6926
    }
6927
}
6928
6929
/// Check whether any pattern in a case prong matches unconditionally.
6930
/// A plain `_` or an all-binding array pattern (e.g. `[x, y]`) qualifies.
6931
/// Note: top-level identifiers in `case` are comparisons, not bindings,
6932
/// so they do not count as wildcards.
6933
fn hasWildcardPattern(patterns: *mut [*ast::Node]) -> bool {
6934
    for pattern in patterns {
6935
        match pattern.value {
6936
            case ast::NodeValue::Placeholder => return true,
6937
            case ast::NodeValue::ArrayLit(items) => {
6938
                if isIrrefutableArrayPattern(items) {
6939
                    return true;
6940
                }
6941
            }
6942
            else => {}
6943
        }
6944
    }
6945
    return false;
6946
}
6947
6948
/// Check whether all elements of an array pattern are irrefutable.
6949
/// Inside array patterns, identifiers are bindings, not comparisons.
6950
fn isIrrefutableArrayPattern(items: *mut [*ast::Node]) -> bool {
6951
    for item in items {
6952
        match item.value {
6953
            case ast::NodeValue::Ident(_), ast::NodeValue::Placeholder => {}
6954
            case ast::NodeValue::ArrayLit(inner) => {
6955
                if not isIrrefutableArrayPattern(inner) {
6956
                    return false;
6957
                }
6958
            }
6959
            else => return false,
6960
        }
6961
    }
6962
    return true;
6963
}
6964
6965
/// Analyze a match prong, checking for duplicate catch-alls. Returns the
6966
/// unified match type.
6967
fn resolveMatchProng(
6968
    self: *mut Resolver,
6969
    prongNode: *ast::Node,
6970
    prong: ast::MatchProng,
6971
    subjectTy: Type,
6972
    state: *mut MatchState,
6973
    matchType: Type,
6974
    matchBy: MatchBy
6975
) -> Type throws (ResolveError) {
6976
    // Whether this prong is catch-all.
6977
    let mut isCatchAll = false;
6978
6979
    if prong.guard <> nil {
6980
        set state.isConst = false;
6981
    } else {
6982
        match prong.arm {
6983
            case ast::ProngArm::Binding(_),
6984
                 ast::ProngArm::Else => set isCatchAll = true,
6985
            case ast::ProngArm::Case(patterns) => set isCatchAll = hasWildcardPattern(patterns),
6986
        }
6987
    }
6988
    if isCatchAll {
6989
        if state.catchAll {
6990
            throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll);
6991
        }
6992
        set state.catchAll = true;
6993
    }
6994
    setProngCatchAll(self, prongNode, isCatchAll);
6995
6996
    return try visitMatchProng(self, prongNode, prong, subjectTy, matchType, matchBy);
6997
}
6998
6999
/// Analyze a `match` expression. Dispatches to specialized functions based on
7000
/// the subject type.
7001
fn resolveMatch(self: *mut Resolver, node: *ast::Node, sw: ast::Match) -> Type
7002
    throws (ResolveError)
7003
{
7004
    let subjectTy = try infer(self, sw.subject);
7005
    let subject = unwrapMatchSubject(subjectTy);
7006
7007
    if let case Type::Optional(inner) = subject.effectiveTy {
7008
        try resolveMatchOptional(self, node, sw, inner, subject.by);
7009
    } else if let case Type::Nominal(NominalType::Union(u)) = subject.effectiveTy {
7010
        try resolveMatchUnion(self, node, sw, subject.effectiveTy, u, subject.by);
7011
    } else {
7012
        try resolveMatchGeneric(self, node, sw, subject.effectiveTy);
7013
    }
7014
7015
    // Mark last non-guarded prong as exhaustive.
7016
    let lastProng = sw.prongs[sw.prongs.len - 1];
7017
    let case ast::NodeValue::MatchProng(p) = lastProng.value
7018
        else panic "resolveMatch: expected match prong";
7019
    if p.guard == nil {
7020
        setProngCatchAll(self, lastProng, true);
7021
    }
7022
    let ty = typeFor(self, node) else {
7023
        return Type::Void;
7024
    };
7025
    return ty;
7026
}
7027
7028
/// Analyze a `match` expression on an optional subject.
7029
fn resolveMatchOptional(
7030
    self: *mut Resolver,
7031
    node: *ast::Node,
7032
    sw: ast::Match,
7033
    innerTy: *Type,
7034
    matchBy: MatchBy
7035
) -> Type throws (ResolveError)
7036
{
7037
    let subjectTy = Type::Optional(innerTy);
7038
    let prongs = sw.prongs;
7039
    let mut hasValue = false;
7040
    let mut hasNil = false;
7041
    let mut catchAll = false;
7042
    let mut matchType = Type::Never;
7043
7044
    for prongNode in prongs {
7045
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
7046
            else panic "resolveMatchOptional: expected match prong";
7047
7048
        let mut isCatchAll = false;
7049
        if prong.guard == nil {
7050
            match prong.arm {
7051
                case ast::ProngArm::Else => set isCatchAll = true,
7052
                case ast::ProngArm::Case(patterns) => set isCatchAll = hasWildcardPattern(patterns),
7053
                case ast::ProngArm::Binding(_) => {
7054
                    // For optionals, a binding does *not* always match.
7055
                }
7056
            }
7057
        }
7058
        if isCatchAll {
7059
            if catchAll {
7060
                throw emitError(self, prongNode, ErrorKind::DuplicateCatchAll);
7061
            }
7062
            set catchAll = true;
7063
        }
7064
        setProngCatchAll(self, prongNode, isCatchAll);
7065
        set matchType = try visitMatchProng(self, prongNode, prong, subjectTy, matchType, matchBy);
7066
7067
        // Track coverage. Guarded prongs don't count as covering a case.
7068
        if prong.guard == nil {
7069
            if let case ast::ProngArm::Binding(_) = prong.arm {
7070
                if hasValue {
7071
                    throw emitError(self, prongNode, ErrorKind::DuplicateMatchPattern);
7072
                }
7073
                set hasValue = true;
7074
            } else if let case ast::ProngArm::Case(patterns) = prong.arm {
7075
                for pat in patterns {
7076
                    if let case ast::NodeValue::Nil = pat.value {
7077
                        if hasNil {
7078
                            throw emitError(self, pat, ErrorKind::DuplicateMatchPattern);
7079
                        }
7080
                        set hasNil = true;
7081
                    }
7082
                }
7083
            }
7084
        }
7085
    }
7086
7087
    // Check exhaustiveness.
7088
    if not catchAll {
7089
        if not hasValue {
7090
            throw emitError(self, node, ErrorKind::OptionalMatchMissingValue);
7091
        }
7092
        if not hasNil {
7093
            throw emitError(self, node, ErrorKind::OptionalMatchMissingNil);
7094
        }
7095
    } else if hasValue and hasNil {
7096
        throw emitError(self, node, ErrorKind::UnreachableElse);
7097
    }
7098
    return setNodeType(self, node, matchType);
7099
}
7100
7101
/// Analyze a `match` expression on a union subject.
7102
fn resolveMatchUnion(
7103
    self: *mut Resolver,
7104
    node: *ast::Node,
7105
    sw: ast::Match,
7106
    subjectTy: Type,
7107
    info: UnionType,
7108
    matchBy: MatchBy
7109
) -> Type throws (ResolveError) {
7110
    let prongs = sw.prongs;
7111
    let mut covered: [bool; MAX_UNION_VARIANTS] = [false; MAX_UNION_VARIANTS];
7112
    let mut coveredCount: u32 = 0;
7113
    let mut state = MatchState { catchAll: false, isConst: false };
7114
    let mut matchType = Type::Never;
7115
7116
    for prongNode in prongs {
7117
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
7118
            else panic "resolveMatchUnion: expected match prong";
7119
7120
        set matchType = try resolveMatchProng(self, prongNode, prong, subjectTy, &mut state, matchType, matchBy);
7121
7122
        // Guarded prongs don't count as covering. Patterns with nested
7123
        // refining sub-patterns (e.g. matching different inner union variants)
7124
        // don't count as duplicates or as fully covering.
7125
        if prong.guard == nil {
7126
            if let case ast::ProngArm::Case(patterns) = prong.arm {
7127
                for pattern in patterns {
7128
                    if let case NodeExtra::UnionVariant { ordinal: ix, .. } = self.nodeData.entries[pattern.id].extra {
7129
                        if not hasNestedRefiningPattern(self, pattern) {
7130
                            if covered[ix] {
7131
                                throw emitError(self, pattern, ErrorKind::DuplicateMatchPattern);
7132
                            }
7133
                            set covered[ix] = true;
7134
                            set coveredCount += 1;
7135
                        }
7136
                    }
7137
                }
7138
            }
7139
        }
7140
    }
7141
    // Check that all variants are covered.
7142
    if not state.catchAll {
7143
        for variant, i in info.variants {
7144
            if not covered[i] {
7145
                throw emitError(
7146
                    self, node, ErrorKind::UnionMatchNonExhaustive(variant.name)
7147
                );
7148
            }
7149
        }
7150
    } else if coveredCount == info.variants.len as u32 {
7151
        throw emitError(self, node, ErrorKind::UnreachableElse);
7152
    }
7153
    return setNodeType(self, node, matchType);
7154
}
7155
7156
/// Analyze a `match` expression on a generic subject type. Requires exhaustiveness:
7157
/// booleans must cover both `true` and `false`, other types require a catch-all.
7158
fn resolveMatchGeneric(self: *mut Resolver, node: *ast::Node, sw: ast::Match, subjectTy: Type) -> Type
7159
    throws (ResolveError)
7160
{
7161
    let prongs = sw.prongs;
7162
    let mut state = MatchState { catchAll: false, isConst: true };
7163
    let mut matchType = Type::Never;
7164
    let mut hasTrue = false;
7165
    let mut hasFalse = false;
7166
    let mut hasConstCase = false;
7167
7168
    for prongNode in prongs {
7169
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
7170
            else panic "resolveMatchGeneric: expected match prong";
7171
7172
        set matchType = try resolveMatchProng(
7173
            self, prongNode, prong, subjectTy, &mut state, matchType, MatchBy::Value
7174
        );
7175
        // Track boolean coverage. Guarded prongs don't count as covering.
7176
        if let case ast::ProngArm::Case(patterns) = prong.arm {
7177
            for p in patterns {
7178
                if prong.guard == nil {
7179
                    if let case ast::NodeValue::Bool(val) = p.value {
7180
                        if (val and hasTrue) or (not val and hasFalse) {
7181
                            throw emitError(self, p, ErrorKind::DuplicateMatchPattern);
7182
                        }
7183
                        if val {
7184
                            set hasTrue = true;
7185
                        } else {
7186
                            set hasFalse = true;
7187
                        }
7188
                    }
7189
                }
7190
                // Scalar constant patterns allow the match to be lowered
7191
                // to a switch instruction.
7192
                if let c = constValueEntry(self, p) {
7193
                    match c {
7194
                        case ConstValue::Bool(_), ConstValue::Char(_), ConstValue::Int(_) =>
7195
                            set hasConstCase = true,
7196
                        else =>
7197
                            set state.isConst = false,
7198
                    }
7199
                }
7200
            }
7201
        }
7202
    }
7203
7204
    // Check exhaustiveness.
7205
    if not state.catchAll {
7206
        if let case Type::Bool = subjectTy {
7207
            if not hasTrue {
7208
                throw emitError(self, node, ErrorKind::BoolMatchMissing(true));
7209
            }
7210
            if not hasFalse {
7211
                throw emitError(self, node, ErrorKind::BoolMatchMissing(false));
7212
            }
7213
        } else {
7214
            throw emitError(self, node, ErrorKind::MatchNonExhaustive);
7215
        }
7216
    } else if let case Type::Bool = subjectTy {
7217
        if hasTrue and hasFalse {
7218
            throw emitError(self, node, ErrorKind::UnreachableElse);
7219
        }
7220
    }
7221
    setMatchConst(self, node, state.isConst and hasConstCase);
7222
7223
    return setNodeType(self, node, matchType);
7224
}
7225
7226
/// Analyze a single `match` prong branch. Returns the unified match type.
7227
fn visitMatchProng(
7228
    self: *mut Resolver,
7229
    node: *ast::Node,
7230
    prongNode: ast::MatchProng,
7231
    subjectTy: Type,
7232
    matchType: Type,
7233
    matchBy: MatchBy
7234
) -> Type throws (ResolveError) {
7235
    enterScope(self, node);
7236
    let prongTy = try resolveMatchProngBody(self, prongNode, subjectTy, matchBy) catch e {
7237
        exitScope(self);
7238
        throw e;
7239
    };
7240
    exitScope(self);
7241
    setNodeType(self, node, prongTy);
7242
7243
    return unifyBranches(matchType, prongTy);
7244
}
7245
7246
/// Analyze the contents of a `match` prong while inside the prong scope.
7247
fn resolveMatchProngBody(
7248
    self: *mut Resolver,
7249
    prong: ast::MatchProng,
7250
    subjectTy: Type,
7251
    matchBy: MatchBy
7252
) -> Type throws (ResolveError) {
7253
    match prong.arm {
7254
        case ast::ProngArm::Binding(pat) => {
7255
            // For optionals, bind the unwrapped inner type.
7256
            let mut bindTy = subjectTy;
7257
            if let case Type::Optional(inner) = subjectTy {
7258
                set bindTy = *inner;
7259
            }
7260
            try bindPatternVar(self, pat, bindTy, matchBy);
7261
        }
7262
        case ast::ProngArm::Case(patterns) => {
7263
            for pattern in patterns {
7264
                try resolveCasePattern(self, pattern, subjectTy, IdentMode::Compare, matchBy);
7265
            }
7266
        }
7267
        case ast::ProngArm::Else => {}
7268
    }
7269
    if let g = prong.guard {
7270
        try checkBoolean(self, g);
7271
    }
7272
    return try visit(self, prong.body, Type::Void);
7273
}
7274
7275
/// Ensure a scope access pattern references a compatible union variant.
7276
fn resolveUnionScopePattern(
7277
    self: *mut Resolver,
7278
    pattern: *ast::Node,
7279
    access: ast::Access,
7280
    subjectTy: Type,
7281
    unionType: UnionType
7282
) throws (ResolveError) {
7283
    let patternTy = try visit(self, pattern, subjectTy);
7284
    if not isComparable(patternTy, subjectTy) {
7285
        throw emitTypeMismatch(self, pattern, TypeMismatch {
7286
            expected: subjectTy,
7287
            actual: patternTy,
7288
        });
7289
    }
7290
    let case NodeExtra::UnionVariant { ordinal: index, .. } = self.nodeData.entries[pattern.id].extra else {
7291
        throw emitError(self, pattern, ErrorKind::Internal);
7292
    };
7293
    let variant = &unionType.variants[index];
7294
    // If this variant has a payload, throw an error, since the user hasn't
7295
    // provided one.
7296
    if variant.valueType <> Type::Void {
7297
        throw emitError(self, pattern, ErrorKind::UnionVariantPayloadMissing(variant.name));
7298
    }
7299
}
7300
7301
/// Validate and bind a union constructor call used as a `match` pattern.
7302
fn resolveUnionCallPattern(
7303
    self: *mut Resolver,
7304
    pattern: *ast::Node,
7305
    call: ast::Call,
7306
    subjectTy: Type,
7307
    unionType: UnionType,
7308
    matchBy: MatchBy
7309
) throws (ResolveError) {
7310
    let calleeTy = try checkEqual(self, call.callee, subjectTy);
7311
    let case NodeExtra::UnionVariant { ordinal: index, tag } = self.nodeData.entries[call.callee.id].extra else {
7312
        throw emitError(self, call.callee, ErrorKind::Internal);
7313
    };
7314
    let variant = &unionType.variants[index];
7315
    // Copy variant index to the pattern node for the lowerer.
7316
    setVariantInfo(self, pattern, index, tag);
7317
7318
    if variant.valueType <> Type::Void {
7319
        try bindUnionPatternPayload(self, pattern, call, variant.name, variant.valueType, matchBy);
7320
    } else {
7321
        throw emitError(self, pattern, ErrorKind::UnionVariantPayloadUnexpected(variant.name));
7322
    }
7323
}
7324
7325
/// Bind the payload introduced by a union constructor pattern.
7326
fn bindUnionPatternPayload(
7327
    self: *mut Resolver,
7328
    pattern: *ast::Node,
7329
    call: ast::Call,
7330
    variantName: *[u8],
7331
    payloadTy: Type,
7332
    matchBy: MatchBy
7333
) throws (ResolveError) {
7334
    if call.args.len == 0 {
7335
        throw emitError(
7336
            self, pattern, ErrorKind::UnionVariantPayloadMissing(variantName)
7337
        );
7338
    }
7339
    // All variant payloads are records.
7340
    let recInfo = getRecord(payloadTy)
7341
        else panic "bindUnionPatternPayload: payload is not a record";
7342
7343
    try bindRecordPatternFields(self, pattern, recInfo, matchBy);
7344
}
7345
7346
/// Bind a pattern variable. For ref matches, wraps the type in a pointer.
7347
fn bindPatternVar(self: *mut Resolver, binding: *ast::Node, ty: Type, matchBy: MatchBy)
7348
    throws (ResolveError)
7349
{
7350
    let mut bindTy = ty;
7351
    match matchBy {
7352
        case MatchBy::Value => {}
7353
        case MatchBy::Ref => set bindTy = Type::Pointer(PointerType {
7354
            class: types::PointerClass::Ref,
7355
            target: allocType(self, ty),
7356
            mutable: false,
7357
        }),
7358
        case MatchBy::MutRef => set bindTy = Type::Pointer(PointerType {
7359
            class: types::PointerClass::Ref,
7360
            target: allocType(self, ty),
7361
            mutable: true,
7362
        }),
7363
    }
7364
    match binding.value {
7365
        case ast::NodeValue::Placeholder => {
7366
            // Nothing to do.
7367
        }
7368
        case ast::NodeValue::Ident(_) => {
7369
            try bindValueIdent(self, binding, binding, bindTy, false, 0, 0);
7370
        }
7371
        else => {
7372
            // Nested pattern: recursively resolve (record destructuring,
7373
            // union variant, scope access, call, literals, etc).
7374
            try resolveCasePattern(self, binding, ty, IdentMode::Bind, matchBy);
7375
        }
7376
    }
7377
}
7378
7379
/// Bind record pattern fields to variables in the current scope.
7380
fn bindRecordPatternFields(
7381
    self: *mut Resolver,
7382
    pattern: *ast::Node,
7383
    recInfo: RecordType,
7384
    matchBy: MatchBy
7385
) throws (ResolveError) {
7386
    match pattern.value {
7387
        case ast::NodeValue::Call(call) => {
7388
            // Unlabeled patterns: `S(x, y)`.
7389
            try checkRecordArity(self, call.args, recInfo, pattern);
7390
7391
            for binding, i in call.args {
7392
                let fieldType = recInfo.fields[i].fieldType;
7393
                try bindPatternVar(self, binding, fieldType, matchBy);
7394
            }
7395
        }
7396
        case ast::NodeValue::RecordLit(lit) => {
7397
            // Labeled patterns: `T { x, y }` or `T { x: binding }`.
7398
            if not lit.ignoreRest {
7399
                try checkRecordArity(self, lit.fields, recInfo, pattern);
7400
            }
7401
            for fieldNode in lit.fields {
7402
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
7403
                    else panic "expected RecordLitField";
7404
7405
                // Brace patterns require labeled fields.
7406
                let label = field.label else panic "expected labeled field";
7407
                let fieldName = try nodeName(self, label);
7408
                let fieldIndex = findRecordField(&recInfo, fieldName)
7409
                    else throw emitError(self, fieldNode, ErrorKind::RecordFieldUnknown(fieldName));
7410
                let fieldType = recInfo.fields[fieldIndex].fieldType;
7411
                // Store field index for the lowerer.
7412
                setRecordFieldIndex(self, fieldNode, fieldIndex);
7413
                try bindPatternVar(self, field.value, fieldType, matchBy);
7414
            }
7415
        }
7416
        else => throw emitError(self, pattern, ErrorKind::Internal)
7417
    }
7418
}
7419
7420
/// Validate and bind a record literal pattern for matching labeled union variants.
7421
fn resolveUnionRecordPattern(
7422
    self: *mut Resolver,
7423
    pattern: *ast::Node,
7424
    lit: ast::RecordLit,
7425
    subjectTy: Type,
7426
    unionType: UnionType,
7427
    matchBy: MatchBy
7428
) throws (ResolveError) {
7429
    let typeName = lit.typeName else {
7430
        throw emitError(self, pattern, ErrorKind::Internal);
7431
    };
7432
    // Verify the type matches the subject.
7433
    let patternTy = try visit(self, typeName, subjectTy);
7434
    if not isComparable(patternTy, subjectTy) {
7435
        throw emitTypeMismatch(self, pattern, TypeMismatch {
7436
            expected: subjectTy,
7437
            actual: patternTy,
7438
        });
7439
    }
7440
    let case NodeExtra::UnionVariant { ordinal: index, tag } = self.nodeData.entries[typeName.id].extra else {
7441
        throw emitError(self, typeName, ErrorKind::Internal);
7442
    };
7443
    let variant = &unionType.variants[index];
7444
7445
    // Copy variant index to the pattern node for the lowerer.
7446
    setVariantInfo(self, pattern, index, tag);
7447
7448
    if variant.valueType == Type::Void {
7449
        throw emitError(self, pattern, ErrorKind::UnionVariantPayloadUnexpected(variant.name));
7450
    }
7451
    let recInfo = getRecord(variant.valueType)
7452
        else panic "resolveUnionRecordPattern: payload is not a record";
7453
7454
    try bindRecordPatternFields(self, pattern, recInfo, matchBy);
7455
}
7456
7457
/// Analyze a pattern appearing in a union case.
7458
fn resolveUnionPattern(
7459
    self: *mut Resolver,
7460
    pattern: *ast::Node,
7461
    subjectTy: Type,
7462
    unionType: UnionType,
7463
    matchBy: MatchBy
7464
) throws (ResolveError) {
7465
    match pattern.value {
7466
        case ast::NodeValue::ScopeAccess(access) =>
7467
            try resolveUnionScopePattern(self, pattern, access, subjectTy, unionType),
7468
        case ast::NodeValue::Call(call) =>
7469
            try resolveUnionCallPattern(self, pattern, call, subjectTy, unionType, matchBy),
7470
        case ast::NodeValue::RecordLit(lit) =>
7471
            try resolveUnionRecordPattern(self, pattern, lit, subjectTy, unionType, matchBy),
7472
        else => {
7473
            let patternTy = try visit(self, pattern, subjectTy);
7474
            throw emitTypeMismatch(self, pattern, TypeMismatch {
7475
                expected: subjectTy,
7476
                actual: patternTy,
7477
            });
7478
        }
7479
    }
7480
}
7481
7482
/// Return whether a case pattern introduces value bindings.
7483
fn casePatternIntroducesBindings(pattern: *ast::Node, nested: bool) -> bool {
7484
    match pattern.value {
7485
        case ast::NodeValue::Ident(_) => return nested,
7486
        case ast::NodeValue::Call(call) => {
7487
            for arg in call.args {
7488
                if casePatternIntroducesBindings(arg, true) {
7489
                    return true;
7490
                }
7491
            }
7492
        }
7493
        case ast::NodeValue::RecordLit(lit) => {
7494
            for fieldNode in lit.fields {
7495
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
7496
                    else continue;
7497
                if casePatternIntroducesBindings(field.value, true) {
7498
                    return true;
7499
                }
7500
            }
7501
        }
7502
        case ast::NodeValue::ArrayLit(items) => {
7503
            for item in items {
7504
                if casePatternIntroducesBindings(item, true) {
7505
                    return true;
7506
                }
7507
            }
7508
        }
7509
        else => {}
7510
    }
7511
    return false;
7512
}
7513
7514
/// Analyze a `let-else` guard.
7515
fn resolveLetElse(self: *mut Resolver, node: *ast::Node, letElse: ast::LetElse) -> Type
7516
    throws (ResolveError)
7517
{
7518
    let pat = &letElse.pattern;
7519
    let exprTy = try infer(self, pat.scrutinee);
7520
7521
    match pat.kind {
7522
        case ast::PatternKind::Binding => {
7523
            // Simple binding requires an optional expression.
7524
            let case Type::Optional(inner) = exprTy else {
7525
                throw emitError(self, pat.scrutinee, ErrorKind::ExpectedOptional);
7526
            };
7527
            let payloadTy = *inner;
7528
            let _ = try bindValueIdent(self, pat.pattern, node, payloadTy, pat.mutable, 0, 0);
7529
            // The `else` branch supplies the binding when the optional is nil.
7530
            try checkAssignable(self, letElse.elseBranch, payloadTy);
7531
            return setNodeType(self, node, Type::Void);
7532
        }
7533
        case ast::PatternKind::Case => {
7534
            // Resolve the failure path before introducing success-only bindings.
7535
            let elseTy = try checkAssignable(self, letElse.elseBranch, exprTy);
7536
            try resolveCasePattern(
7537
                self,
7538
                pat.pattern,
7539
                exprTy,
7540
                IdentMode::Compare,
7541
                MatchBy::Value,
7542
            );
7543
            if let guardExpr = pat.guard {
7544
                try checkBoolean(self, guardExpr);
7545
            }
7546
            if elseTy <> Type::Never and
7547
               casePatternIntroducesBindings(pat.pattern, false)
7548
            {
7549
                throw emitError(
7550
                    self,
7551
                    letElse.elseBranch,
7552
                    ErrorKind::LinearLetElseMustTerminate,
7553
                );
7554
            }
7555
        }
7556
    }
7557
    return setNodeType(self, node, Type::Void);
7558
}
7559
7560
/// Analyze builtin function calls like `@sizeOf(T)` and `@alignOf(T)`.
7561
fn resolveBuiltinCall(
7562
    self: *mut Resolver,
7563
    node: *ast::Node,
7564
    kind: ast::Builtin,
7565
    args: *mut [*ast::Node]
7566
) -> Type throws (ResolveError) {
7567
    // Handle `@sliceOf(ptr, len)` and `@sliceOf(ptr, len, cap)`.
7568
    if kind == ast::Builtin::SliceOf {
7569
        if args.len <> 2 and args.len <> 3 {
7570
            throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch {
7571
                expected: 2,
7572
                actual: args.len as u32,
7573
            }));
7574
        }
7575
        let ptrType = try visit(self, args[0], Type::Unknown);
7576
        let case Type::Pointer(ptr) = ptrType else {
7577
            throw emitError(self, node, ErrorKind::ExpectedPointer);
7578
        };
7579
        let _ = try checkAssignable(self, args[1], Type::U32);
7580
        if args.len == 3 {
7581
            let _ = try checkAssignable(self, args[2], Type::U32);
7582
        }
7583
        return setNodeType(self, node, Type::Slice(SliceType {
7584
            class: ptr.class,
7585
            item: ptr.target,
7586
            mutable: ptr.mutable,
7587
        }));
7588
    }
7589
    if args.len <> 1 {
7590
        throw emitError(self, node, ErrorKind::BuiltinArgCountMismatch(CountMismatch {
7591
            expected: 1,
7592
            actual: args.len as u32,
7593
        }));
7594
    }
7595
7596
    let ty = try resolveValueType(self, args[0]);
7597
    // Ensure the type body is resolved before computing layout.
7598
    // TODO: Somehow, ensuring the type is resolved should just happen all
7599
    // the time, lazily.
7600
    try ensureTypeResolved(self, ty, args[0]);
7601
    if containsGenericParameter(ty) {
7602
        throw emitError(self, args[0], ErrorKind::GenericLayoutRequired);
7603
    }
7604
    // TODO: This should be stored in `symbol` instead of having to recompute it.
7605
    // That way there's a canonical place to look for code gen.
7606
    let layout = getTypeLayout(ty);
7607
7608
    // Evaluate the built-in.
7609
    let mut value: u32 = undefined;
7610
    match kind {
7611
        case ast::Builtin::SizeOf => {
7612
            set value = layout.size;
7613
        },
7614
        case ast::Builtin::AlignOf => {
7615
            set value = layout.alignment;
7616
        },
7617
        case ast::Builtin::SliceOf => {
7618
            panic "unreachable: @sliceOf handled above";
7619
        }
7620
    }
7621
    // Record as constant value for constant folding.
7622
    setNodeConstValue(self, node, ConstValue::Int(ConstInt {
7623
        magnitude: value as u64,
7624
        bits: 32,
7625
        signed: false,
7626
        negative: false,
7627
    }));
7628
    return setNodeType(self, node, Type::U32);
7629
}
7630
7631
/// Validate call arguments against a function type: check argument count,
7632
/// type-check each argument, and verify that throwing functions use `try`.
7633
fn checkCallArgs(self: *mut Resolver, node: *ast::Node, call: ast::Call, info: *FnType, ctx: CallCtx)
7634
    throws (ResolveError)
7635
{
7636
    if ctx == CallCtx::Normal and info.throwList.len > 0 {
7637
        throw emitError(self, node, ErrorKind::MissingTry);
7638
    }
7639
    if call.args.len <> info.paramTypes.len as u32 {
7640
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
7641
            expected: info.paramTypes.len as u32,
7642
            actual: call.args.len,
7643
        }));
7644
    }
7645
    for argNode, i in call.args {
7646
        let expectedTy = *info.paramTypes[i];
7647
7648
        try checkAssignable(self, argNode, expectedTy);
7649
    }
7650
}
7651
7652
/// Unify one symbolic parameter type with exact call-site evidence.
7653
fn inferGenericArgument(
7654
    self: *mut Resolver,
7655
    pattern: Type,
7656
    actual: Type,
7657
    params: *[*GenericParamType],
7658
    inferred: *mut [?*Type],
7659
) -> bool {
7660
    if let case Type::Parameter(param) = pattern {
7661
        let mut evidence = actual;
7662
        match actual {
7663
            case Type::Unknown, Type::Nil, Type::Undefined => return true,
7664
            case Type::Int => set evidence = Type::I64,
7665
            else => {},
7666
        }
7667
        for candidate, i in params {
7668
            if candidate == param {
7669
                if let prior = inferred[i] {
7670
                    return typesEqual(*prior, evidence);
7671
                }
7672
                set inferred[i] = allocType(self, evidence);
7673
                return true;
7674
            }
7675
        }
7676
        return typesEqual(pattern, evidence);
7677
    }
7678
    if typesEqual(pattern, actual) {
7679
        return true;
7680
    }
7681
    if not containsGenericParameter(pattern) {
7682
        return true;
7683
    }
7684
    match pattern {
7685
        case Type::Pointer(pointer) => {
7686
            let case Type::Pointer(actualPointer) = actual else return false;
7687
            return pointer.class == actualPointer.class
7688
                and pointer.mutable == actualPointer.mutable
7689
                and inferGenericArgument(
7690
                    self,
7691
                    *pointer.target,
7692
                    *actualPointer.target,
7693
                    params,
7694
                    inferred,
7695
                );
7696
        }
7697
        case Type::Slice(slice) => {
7698
            let case Type::Slice(actualSlice) = actual else return false;
7699
            return slice.class == actualSlice.class
7700
                and slice.mutable == actualSlice.mutable
7701
                and inferGenericArgument(
7702
                    self,
7703
                    *slice.item,
7704
                    *actualSlice.item,
7705
                    params,
7706
                    inferred,
7707
                );
7708
        }
7709
        case Type::Optional(inner) => {
7710
            let case Type::Optional(actualInner) = actual else return false;
7711
            return inferGenericArgument(
7712
                self, *inner, *actualInner, params, inferred
7713
            );
7714
        }
7715
        case Type::Array(array) => {
7716
            let case Type::Array(actualArray) = actual else return false;
7717
            return array.length == actualArray.length and inferGenericArgument(
7718
                self, *array.item, *actualArray.item, params, inferred
7719
            );
7720
        }
7721
        case Type::GenericDataApply(application) => {
7722
            let case Type::Nominal(nominal) = actual else return false;
7723
            let concrete = genericDataSpecializationForNominal(self, nominal)
7724
                else return false;
7725
            if concrete.template <> application.template
7726
                or concrete.args.len <> application.args.len
7727
            {
7728
                return false;
7729
            }
7730
            for arg, i in application.args {
7731
                if not inferGenericArgument(
7732
                    self, *arg, *concrete.args[i], params, inferred
7733
                ) {
7734
                    return false;
7735
                }
7736
            }
7737
            return true;
7738
        }
7739
        else => return false,
7740
    }
7741
}
7742
7743
/// Infer and resolve a direct call to a generic function template.
7744
fn resolveInferredGenericCall(
7745
    self: *mut Resolver,
7746
    callee: *ast::Node,
7747
    call: ast::Call,
7748
    expected: Type,
7749
) -> ?*FnType throws (ResolveError) {
7750
    let templateSym = findGenericCandidateSymbol(self, callee) else return nil;
7751
    let template = genericTemplateFor(self, templateSym) else return nil;
7752
    let signature = template.signature else return nil;
7753
    if call.args.len <> signature.paramTypes.len {
7754
        return nil;
7755
    }
7756
    let mut inferred: [?*Type; MAX_FN_PARAMS] = undefined;
7757
    for i in 0..inferred.len {
7758
        set inferred[i] = nil;
7759
    }
7760
    for argNode, i in call.args {
7761
        let actual = try infer(self, argNode);
7762
        if not inferGenericArgument(
7763
            self,
7764
            *signature.paramTypes[i],
7765
            actual,
7766
            template.params,
7767
            &mut inferred[..],
7768
        ) {
7769
            throw emitError(self, argNode, ErrorKind::GenericInferenceConflict);
7770
        }
7771
    }
7772
    if expected <> Type::Unknown and expected <> Type::Void and not inferGenericArgument(
7773
        self,
7774
        *signature.returnType,
7775
        expected,
7776
        template.params,
7777
        &mut inferred[..],
7778
    ) {
7779
        throw emitError(self, callee, ErrorKind::GenericInferenceConflict);
7780
    }
7781
    let a = alloc::arenaAllocator(&mut self.arena);
7782
    let mut args: *mut [*Type] = &mut [];
7783
    for _, i in template.params {
7784
        let arg = inferred[i] else {
7785
            throw emitError(
7786
                self, callee, ErrorKind::GenericInferenceIncomplete
7787
            );
7788
        };
7789
        args.append(arg, a);
7790
    }
7791
    for arg, i in args {
7792
        if not containsGenericParameter(*arg) {
7793
            for bound in template.params[i].bounds {
7794
                if findInstance(self, bound, *arg) == nil {
7795
                    throw emitError(
7796
                        self,
7797
                        callee,
7798
                        ErrorKind::GenericBoundUnsatisfied(bound.name),
7799
                    );
7800
                }
7801
            }
7802
        }
7803
    }
7804
    let sub = Substitution { params: template.params, args: &args[..] };
7805
    let applied = try substituteType(self, Type::Fn(signature), &sub, callee);
7806
    let case Type::Fn(appliedFn) = applied
7807
        else throw emitError(self, callee, ErrorKind::Internal);
7808
    let caller = currentGenericTemplateSymbol(self);
7809
    if caller == nil {
7810
        if let existing = findGenericFnSpecialization(
7811
            self, templateSym, &args[..]
7812
        ) {
7813
            setNodeSymbol(self, callee, templateSym);
7814
            setNodeType(self, callee, Type::Fn(existing.fnType));
7815
            set self.nodeData.entries[callee.id].extra =
7816
                NodeExtra::GenericFnCall(existing);
7817
            return existing.fnType;
7818
        }
7819
    }
7820
    recordGenericFnDependency(
7821
        self, callee, caller, templateSym, &args[..], appliedFn
7822
    );
7823
    return appliedFn;
7824
}
7825
7826
/// Resolve `Trait::method(receiver, ...)` for a rigid bounded parameter.
7827
fn resolveQualifiedGenericBoundCall(
7828
    self: *mut Resolver,
7829
    node: *ast::Node,
7830
    call: ast::Call,
7831
    ctx: CallCtx,
7832
) -> ?Type throws (ResolveError) {
7833
    let case ast::NodeValue::ScopeAccess(access) = call.callee.value
7834
        else return nil;
7835
    if currentGenericTemplateSymbol(self) == nil or call.args.len == 0 {
7836
        return nil;
7837
    }
7838
    let traitSym = try resolveNamePath(self, access.parent);
7839
    let case SymbolData::Trait(traitInfo) = traitSym.data else return nil;
7840
    let receiverTy = try infer(self, call.args[0]);
7841
    let case Type::Pointer(receiver) = receiverTy else return nil;
7842
    let case Type::Parameter(param) = *receiver.target else return nil;
7843
    let mut hasBound = false;
7844
    for bound in param.bounds {
7845
        if bound == traitInfo {
7846
            set hasBound = true;
7847
            break;
7848
        }
7849
    }
7850
    if not hasBound {
7851
        return nil;
7852
    }
7853
    if isUnsafePointerType(receiverTy) {
7854
        try requireUnsafe(self, call.args[0]);
7855
    }
7856
    let methodName = try nodeName(self, access.child);
7857
    let method = findTraitMethod(traitInfo, methodName)
7858
        else throw emitError(
7859
            self, access.child, ErrorKind::RecordFieldUnknown(methodName)
7860
        );
7861
    if method.mutable and not receiver.mutable {
7862
        throw emitError(self, call.args[0], ErrorKind::ImmutableBinding);
7863
    }
7864
    let selfParam: [*GenericParamType; 1] = [method.owner.selfType];
7865
    let selfArg: [*Type; 1] = [allocType(self, Type::Parameter(param))];
7866
    let sub = Substitution {
7867
        params: &selfParam[..],
7868
        args: &selfArg[..],
7869
    };
7870
    let substituted = try substituteType(
7871
        self, Type::Fn(method.fnType), &sub, node
7872
    );
7873
    let case Type::Fn(methodFn) = substituted
7874
        else throw emitError(self, node, ErrorKind::Internal);
7875
    let a = alloc::arenaAllocator(&mut self.arena);
7876
    let mut params: *mut [*Type] = &mut [];
7877
    params.append(allocType(self, receiverTy), a);
7878
    for methodParam in methodFn.paramTypes {
7879
        params.append(methodParam, a);
7880
    }
7881
    let fullFn = allocFnType(self, FnType {
7882
        paramTypes: &params[..],
7883
        returnType: methodFn.returnType,
7884
        throwList: methodFn.throwList,
7885
        isUnsafe: methodFn.isUnsafe,
7886
        localCount: 0,
7887
    });
7888
    try checkUnsafeCall(self, call.callee, fullFn);
7889
    try checkCallArgs(self, node, call, fullFn, ctx);
7890
    setNodeSymbol(self, access.parent, traitSym);
7891
    setNodeType(self, call.callee, Type::Fn(fullFn));
7892
    setGenericBoundMethodCall(
7893
        self, node, param, traitInfo, method.index, true
7894
    );
7895
    return setNodeType(self, node, *methodFn.returnType);
7896
}
7897
7898
/// Analyze a function call expression.
7899
fn resolveCall(
7900
    self: *mut Resolver,
7901
    node: *ast::Node,
7902
    call: ast::Call,
7903
    ctx: CallCtx,
7904
    expected: Type,
7905
) -> Type throws (ResolveError)
7906
{
7907
    // Intercept method calls on slices before inferring the callee.
7908
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
7909
        let parentTy = try infer(self, access.parent);
7910
        if isUnsafePointerType(parentTy) {
7911
            try requireUnsafe(self, access.parent);
7912
        }
7913
7914
        let subjectTy = autoDeref(parentTy);
7915
7916
        if let case Type::Slice(slice) = subjectTy {
7917
            let methodName = try nodeName(self, access.child);
7918
            if methodName == "append" {
7919
                return try resolveSliceAppend(
7920
                    self, node, access.parent, parentTy, call.args, slice.item, slice.mutable
7921
                );
7922
            }
7923
            if methodName == "delete" {
7924
                return try resolveSliceDelete(
7925
                    self, node, access.parent, call.args, slice.item, slice.mutable
7926
                );
7927
            }
7928
        }
7929
    }
7930
    if let bounded = try resolveQualifiedGenericBoundCall(
7931
        self, node, call, ctx
7932
    ) {
7933
        return bounded;
7934
    }
7935
    if let inferred = try resolveInferredGenericCall(
7936
        self, call.callee, call, expected
7937
    ) {
7938
        try checkUnsafeCall(self, call.callee, inferred);
7939
        try checkCallArgs(self, node, call, inferred, ctx);
7940
        return setNodeType(self, node, *inferred.returnType);
7941
    }
7942
    let calleeTy = try infer(self, call.callee);
7943
    if let case Type::Fn(info) = calleeTy {
7944
        try checkUnsafeCall(self, call.callee, info);
7945
    }
7946
7947
    // Check if callee is a union variant and dispatch to constructor handler.
7948
    // TODO: Move this out. We should decide on this earlier, based on the callee.
7949
    if let calleeSym = symbolFor(self, call.callee) {
7950
        if let case SymbolData::Variant { .. } = calleeSym.data {
7951
            let case Type::Nominal(unionType) = calleeTy
7952
                else throw emitError(self, call.callee, ErrorKind::Internal);
7953
            return try resolveUnionConstructorCall(self, node, call, unionType);
7954
        }
7955
        // Check if callee is an unlabeled record type for constructor call syntax.
7956
        if let case SymbolData::Type(ty) = calleeSym.data {
7957
            // Ensure the record body is resolved before checking if labeled.
7958
            try ensureNominalResolved(self, ty, call.callee);
7959
            if let case NominalType::Record(recInfo) = *ty {
7960
                if not recInfo.labeled {
7961
                    return try resolveRecordConstructorCall(self, node, call, ty);
7962
                }
7963
            }
7964
        }
7965
    }
7966
7967
    // Check if we have a trait method call, ie. callee is a trait object.
7968
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
7969
        let mut parentTy = Type::Unknown;
7970
        if let t = typeFor(self, access.parent) {
7971
            set parentTy = t;
7972
        }
7973
        let subjectTy = autoDeref(parentTy);
7974
7975
        if let case Type::Parameter(param) = subjectTy; param.bounds.len > 0 {
7976
            let methodName = try nodeName(self, access.child);
7977
            let selected = try findGenericBoundMethod(
7978
                self, access.child, param, methodName
7979
            );
7980
            let case Type::Fn(info) = calleeTy
7981
                else throw emitError(self, call.callee, ErrorKind::Internal);
7982
            if selected.method.mutable {
7983
                let mut isMutPtr = false;
7984
                if let case Type::Pointer(pointer) = parentTy {
7985
                    set isMutPtr = pointer.mutable;
7986
                }
7987
                if not isMutPtr and not (try canBorrowMutFrom(self, access.parent)) {
7988
                    throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
7989
                }
7990
            }
7991
            try checkUnsafeCall(self, call.callee, info);
7992
            try checkCallArgs(self, node, call, info, ctx);
7993
            setGenericBoundMethodCall(
7994
                self,
7995
                node,
7996
                param,
7997
                selected.traitInfo,
7998
                selected.method.index,
7999
                false,
8000
            );
8001
            return setNodeType(self, node, *info.returnType);
8002
        }
8003
8004
        if let case Type::TraitObject(traitObject) = subjectTy {
8005
            let methodName = try nodeName(self, access.child);
8006
            let method = findTraitMethod(traitObject.traitInfo, methodName)
8007
                else throw emitError(self, access.child, ErrorKind::RecordFieldUnknown(methodName));
8008
            // Reject mutable-receiver methods called on immutable trait objects.
8009
            if method.mutable and not traitObject.mutable {
8010
                throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
8011
            }
8012
            try checkCallArgs(self, node, call, method.fnType, ctx);
8013
            setTraitMethodCall(self, node, traitObject.traitInfo, method.index);
8014
            return setNodeType(self, node, *method.fnType.returnType);
8015
        }
8016
8017
        // Check for a standalone method call on a concrete type.
8018
        if let case Type::Nominal(_) = subjectTy {
8019
            let methodName = try nodeName(self, access.child);
8020
            if let method = findMethod(self, subjectTy, methodName) {
8021
                // Reject mutable-receiver methods on immutable bindings.
8022
                // If the parent is already a mutable pointer, the receiver is fine.
8023
                // Otherwise, check that the parent can yield a mutable borrow.
8024
                if method.mutable {
8025
                    let mut isMutPtr = false;
8026
                    if let case Type::Pointer(pointer) = parentTy {
8027
                        set isMutPtr = pointer.mutable;
8028
                    }
8029
                    if not isMutPtr and not (try canBorrowMutFrom(self, access.parent)) {
8030
                        throw emitError(self, access.parent, ErrorKind::ImmutableBinding);
8031
                    }
8032
                }
8033
                // Check arguments (excluding receiver).
8034
                try checkCallArgs(self, node, call, method.fnType, ctx);
8035
                set self.nodeData.entries[node.id].extra = NodeExtra::MethodCall { method };
8036
8037
                return setNodeType(self, node, *method.fnType.returnType);
8038
            }
8039
        }
8040
    }
8041
    let case Type::Fn(info) = calleeTy else {
8042
        throw emitError(self, call.callee, ErrorKind::TypeMismatch(TypeMismatch {
8043
            expected: Type::Unknown,
8044
            actual: calleeTy,
8045
        }));
8046
    };
8047
    try checkCallArgs(self, node, call, info, ctx);
8048
    // Associate function type to callee.
8049
    setNodeType(self, call.callee, calleeTy);
8050
8051
    // Associate return type to call.
8052
    return setNodeType(self, node, *info.returnType);
8053
}
8054
8055
/// Resolve `slice.append(val, allocator)`.
8056
fn resolveSliceAppend(
8057
    self: *mut Resolver,
8058
    node: *ast::Node,
8059
    parent: *ast::Node,
8060
    parentType: Type,
8061
    args: *mut [*ast::Node],
8062
    elemType: *Type,
8063
    mutable: bool
8064
) -> Type throws (ResolveError) {
8065
    if not mutable {
8066
        throw emitError(self, parent, ErrorKind::ImmutableBinding);
8067
    }
8068
    if args.len <> 2 {
8069
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
8070
            expected: 2,
8071
            actual: args.len as u32,
8072
        }));
8073
    }
8074
    // First argument must be assignable to the element type.
8075
    try checkAssignable(self, args[0], *elemType);
8076
    // Second argument: the allocator. We accept any type -- the lowerer
8077
    // reads `.func` and `.ctx` at fixed offsets.
8078
    try visit(self, args[1], Type::Unknown);
8079
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceAppend { elemType };
8080
8081
    // Return the parent's type so the caller can rebind:
8082
    return setNodeType(self, node, parentType);
8083
}
8084
8085
/// Resolve `slice.delete(index)`.
8086
fn resolveSliceDelete(
8087
    self: *mut Resolver,
8088
    node: *ast::Node,
8089
    parent: *ast::Node,
8090
    args: *mut [*ast::Node],
8091
    elemType: *Type,
8092
    mutable: bool
8093
) -> Type throws (ResolveError) {
8094
    if not mutable {
8095
        throw emitError(self, parent, ErrorKind::ImmutableBinding);
8096
    }
8097
    if args.len <> 1 {
8098
        throw emitError(self, node, ErrorKind::FnArgCountMismatch(CountMismatch {
8099
            expected: 1,
8100
            actual: args.len as u32,
8101
        }));
8102
    }
8103
    try checkAssignable(self, args[0], Type::U32);
8104
    set self.nodeData.entries[node.id].extra = NodeExtra::SliceDelete { elemType };
8105
8106
    return setNodeType(self, node, Type::Void);
8107
}
8108
8109
/// Analyze an assignment expression.
8110
fn resolveAssign(self: *mut Resolver, node: *ast::Node, assign: ast::Assign) -> Type
8111
    throws (ResolveError)
8112
{
8113
    // Slice assignment: `slice[range] = value`.
8114
    if let case ast::NodeValue::Subscript { container, index } = assign.left.value {
8115
        if let case ast::NodeValue::Range(range) = index.value {
8116
            try infer(self, index);
8117
            let containerTy = try infer(self, container);
8118
            if not try canBorrowMutFrom(self, container) {
8119
                throw emitError(self, container, ErrorKind::ImmutableBinding);
8120
            }
8121
            let subjectTy = autoDeref(containerTy);
8122
            try checkSliceRangeIndices(self, range);
8123
8124
            let mut item: *Type = undefined;
8125
            let mut capacity: ?u32 = nil;
8126
8127
            if let case Type::Slice(slice) = subjectTy {
8128
                if not slice.mutable {
8129
                    throw emitError(self, container, ErrorKind::ImmutableBinding);
8130
                }
8131
                set item = slice.item;
8132
            } else {
8133
                match subjectTy {
8134
                    case Type::Array(a) => {
8135
                        try validateArraySliceBounds(self, range, a.length, node);
8136
                        set item = a.item;
8137
                        set capacity = a.length;
8138
                    }
8139
                    else => throw emitError(self, container, ErrorKind::ExpectedIndexable),
8140
                }
8141
            }
8142
            // RHS is either a fill value or a source slice.
8143
            let rhsTy = try infer(self, assign.right);
8144
            if let case Type::Slice(source) = rhsTy {
8145
                if *source.item <> *item {
8146
                    throw emitTypeMismatch(
8147
                        self,
8148
                        assign.right,
8149
                        TypeMismatch { expected: *item, actual: *source.item },
8150
                    );
8151
                }
8152
            } else {
8153
                try checkAssignable(self, assign.right, *item);
8154
            }
8155
            setSliceRangeInfo(self, node, SliceRangeInfo { itemType: item, mutable: true, capacity });
8156
            setNodeType(self, assign.left, *item);
8157
8158
            return setNodeType(self, node, Type::Void);
8159
        }
8160
    }
8161
    let leftTy = try infer(self, assign.left);
8162
8163
    // Check if the left-hand side can be assigned to by checking if it's a mutable location.
8164
    if not try canBorrowMutFrom(self, assign.left) {
8165
        throw emitError(self, assign.left, ErrorKind::ImmutableBinding);
8166
    }
8167
    try checkAssignable(self, assign.right, leftTy);
8168
8169
    return setNodeType(self, node, leftTy);
8170
}
8171
8172
/// Ensure slice range bounds are valid `u32` values.
8173
fn checkSliceRangeIndices(self: *mut Resolver, range: ast::Range) throws (ResolveError) {
8174
    if let start = range.start {
8175
        try checkIndex(self, start);
8176
    }
8177
    if let end = range.end {
8178
        try checkIndex(self, end);
8179
    }
8180
}
8181
8182
/// Emit an error when a slice range with compile-tyime values exceeds the array length.
8183
fn validateArraySliceBounds(self: *mut Resolver, range: ast::Range, length: u32, site: *ast::Node) throws (ResolveError) {
8184
    let mut startVal: ?u32 = nil;
8185
    let mut endVal: ?u32 = length;
8186
8187
    if let startNode = range.start {
8188
        if let val = constSliceIndex(self, startNode) {
8189
            set startVal = val;
8190
        }
8191
    }
8192
    if let endNode = range.end {
8193
        if let val = constSliceIndex(self, endNode) {
8194
            set endVal = val;
8195
        }
8196
    }
8197
    if let val = startVal; val > length {
8198
        throw emitError(self, site, ErrorKind::SliceRangeOutOfBounds);
8199
    }
8200
    if let val = endVal; val > length {
8201
        throw emitError(self, site, ErrorKind::SliceRangeOutOfBounds);
8202
    }
8203
    if let start = startVal {
8204
        if let end = endVal; start > end {
8205
            throw emitError(self, site, ErrorKind::SliceRangeOutOfBounds);
8206
        }
8207
    }
8208
}
8209
8210
/// Check that an index expression has an unsigned integer type.
8211
/// Accepts `u8`, `u16`, `u32` and unsuffixed integer literals.
8212
/// Smaller types are widened to `u32` via a numeric cast coercion.
8213
fn checkIndex(self: *mut Resolver, indexNode: *ast::Node) throws (ResolveError) {
8214
    let indexTy = try visit(self, indexNode, Type::U32);
8215
    if indexTy == Type::Int or indexTy == Type::U32 {
8216
        let _ = try expectAssignable(self, Type::U32, indexTy, indexNode);
8217
        return;
8218
    }
8219
    match indexTy {
8220
        case Type::U8, Type::U16 => {
8221
            setNodeCoercion(self, indexNode, Coercion::NumericCast {
8222
                from: indexTy, to: Type::U32,
8223
            });
8224
        }
8225
        else => {
8226
            throw emitTypeMismatch(self, indexNode, TypeMismatch {
8227
                expected: Type::U32,
8228
                actual: indexTy,
8229
            });
8230
        }
8231
    }
8232
}
8233
8234
/// Analyze an array or slice subscript expression.
8235
fn resolveSubscript(self: *mut Resolver, node: *ast::Node, container: *ast::Node, indexNode: *ast::Node) -> Type
8236
    throws (ResolveError)
8237
{
8238
    // Range subscripts always require `&` to form a slice.
8239
    if let case ast::NodeValue::Range(range) = indexNode.value {
8240
        let _ = try infer(self, indexNode);
8241
        let _ = try infer(self, container);
8242
        try checkSliceRangeIndices(self, range);
8243
        throw emitError(self, node, ErrorKind::SliceRequiresAddress);
8244
    }
8245
    let containerTy = try infer(self, container);
8246
    if isUnsafePointerType(containerTy) {
8247
        try requireUnsafe(self, container);
8248
    }
8249
    try checkIndex(self, indexNode);
8250
    let subjectTy = autoDeref(containerTy);
8251
    if let case Type::Slice(slice) = subjectTy {
8252
        return setNodeType(self, node, *slice.item);
8253
    }
8254
8255
    match subjectTy {
8256
        case Type::Array(arrayInfo) => {
8257
            return setNodeType(self, node, *arrayInfo.item);
8258
        }
8259
        case Type::GenericArray { item, .. } => {
8260
            return setNodeType(self, node, *item);
8261
        }
8262
        else => {
8263
            throw emitError(self, container, ErrorKind::ExpectedIndexable);
8264
        }
8265
    }
8266
}
8267
8268
/// Find a record field by name.
8269
fn findRecordField(s: *RecordType, fieldName: *[u8]) -> ?u32 {
8270
    for field, i in s.fields {
8271
        if let name = field.name {
8272
            if name == fieldName {
8273
                return i;
8274
            }
8275
        }
8276
    }
8277
    return nil;
8278
}
8279
8280
/// Analyze a union constructor call with payload.
8281
fn resolveUnionConstructorCall(self: *mut Resolver, node: *ast::Node, call: ast::Call, unionNominal: *NominalType) -> Type
8282
    throws (ResolveError)
8283
{
8284
    // Get the union nominal type.
8285
    let case NominalType::Union(unionType) = *unionNominal
8286
        else panic "resolveUnionConstructorCall: not a union type";
8287
8288
    // Callee was already visited; get the variant index it set.
8289
    let case NodeExtra::UnionVariant { ordinal: index, tag } = self.nodeData.entries[call.callee.id].extra else {
8290
        throw emitError(self, call.callee, ErrorKind::Internal);
8291
    };
8292
    let variant = &unionType.variants[index];
8293
8294
    // Associate variant index with `call` node for the lowerer.
8295
    setVariantInfo(self, node, index, tag);
8296
8297
    // Check if this variant expects a payload.
8298
    let payloadType = variant.valueType;
8299
    if payloadType <> Type::Void {
8300
        let recInfo = getRecord(payloadType)
8301
            else panic "resolveUnionVariantConstructor: payload is not a record";
8302
        try checkRecordConstructorArgs(self, node, call.args, recInfo);
8303
    } else {
8304
        if call.args.len > 0 {
8305
            throw emitError(self, node, ErrorKind::UnionVariantPayloadUnexpected(variant.name));
8306
        }
8307
    }
8308
    return setNodeType(self, node, Type::Nominal(unionNominal));
8309
}
8310
8311
/// Analyze an unlabeled record constructor call.
8312
///
8313
/// Handles the syntax `R(a, b)` for unlabeled records, checking that the
8314
/// number of arguments matches the record's field count and that each argument
8315
/// is assignable to its corresponding field type.
8316
fn resolveRecordConstructorCall(self: *mut Resolver, node: *ast::Node, call: ast::Call, recordType: *NominalType) -> Type
8317
    throws (ResolveError)
8318
{
8319
    let case NominalType::Record(recInfo) = *recordType
8320
        else panic "resolveRecordConstructorCall: not a record type";
8321
8322
    try checkRecordConstructorArgs(self, node, call.args, recInfo);
8323
    return setNodeType(self, node, Type::Nominal(recordType));
8324
}
8325
8326
/// Resolve the type name of a record literal, handling both record types and
8327
/// union variant payloads like `Union::Variant { ... }`.
8328
fn resolveRecordLitType(
8329
    self: *mut Resolver, node: *ast::Node, typeIdent: *ast::Node
8330
) -> ResolvedRecordLitType
8331
    throws (ResolveError)
8332
{
8333
    // Check if this is a scope access that might be a union variant.
8334
    if let case ast::NodeValue::ScopeAccess(access) = typeIdent.value {
8335
        let sym = try resolveAccess(self, typeIdent, access, self.scope);
8336
8337
        // Check if resolved symbol is a union variant.
8338
        if let case SymbolData::Variant { type, ordinal, index, .. } = sym.data {
8339
            let resolved = typeFor(self, typeIdent)
8340
                else throw emitError(self, node, ErrorKind::Internal);
8341
            let case Type::Nominal(unionNominalType) = resolved
8342
                else throw emitError(self, node, ErrorKind::Internal);
8343
8344
            // Get the variant's payload type.
8345
            let case Type::Nominal(payloadInfo) = type
8346
                else throw emitError(self, node, ErrorKind::ExpectedRecord);
8347
8348
            // Store the variant index for the lowerer.
8349
            setVariantInfo(self, node, ordinal, index);
8350
8351
            return ResolvedRecordLitType {
8352
                recordType: payloadInfo,
8353
                resultType: Type::Nominal(unionNominalType),
8354
            };
8355
        }
8356
        // Not a variant, must be a type.
8357
        let case SymbolData::Type(ty) = sym.data
8358
            else throw emitError(self, node, ErrorKind::ExpectedRecord);
8359
        return ResolvedRecordLitType {
8360
            recordType: ty,
8361
            resultType: Type::Nominal(ty),
8362
        };
8363
    }
8364
    // Simple identifier, resolve as type name.
8365
    let tyInfo = try resolveTypeName(self, typeIdent);
8366
    return ResolvedRecordLitType {
8367
        recordType: tyInfo,
8368
        resultType: Type::Nominal(tyInfo),
8369
    };
8370
}
8371
8372
/// Analyze a record literal expression.
8373
fn resolveRecordLit(self: *mut Resolver, node: *ast::Node, lit: ast::RecordLit, hint: Type) -> Type
8374
    throws (ResolveError)
8375
{
8376
    // If no type name, infer an anonymous tuple type.
8377
    let typeIdent = lit.typeName else {
8378
        return try resolveAnonRecordLit(self, node, lit, hint);
8379
    };
8380
    // Resolve the type name, handling both record types and union variants.
8381
    let resolved = try resolveRecordLitType(self, node, typeIdent);
8382
    let tyInfo = resolved.recordType;
8383
    let resultType = resolved.resultType;
8384
8385
    // Lazily resolve record body if not yet done.
8386
    try ensureNominalResolved(self, tyInfo, typeIdent);
8387
    let case NominalType::Record(recordType) = *tyInfo
8388
        else throw emitError(self, node, ErrorKind::ExpectedRecord);
8389
8390
    // Unlabeled records must use constructor call syntax `R(...)`, not brace syntax.
8391
    if not recordType.labeled {
8392
        throw emitError(self, node, ErrorKind::RecordFieldStyleMismatch);
8393
    }
8394
    // Check field count. With `{ .. }` syntax, fewer fields are allowed.
8395
    if lit.fields.len > recordType.fields.len {
8396
        throw emitError(self, node, ErrorKind::RecordFieldCountMismatch(CountMismatch {
8397
            expected: recordType.fields.len as u32,
8398
            actual: lit.fields.len,
8399
        }));
8400
    }
8401
    if not lit.ignoreRest and lit.fields.len < recordType.fields.len {
8402
        let missingName = recordType.fields[lit.fields.len].name else panic;
8403
        throw emitError(self, node, ErrorKind::RecordFieldMissing(missingName));
8404
    }
8405
8406
    // Fields must be in declaration order.
8407
    for fieldNode, idx in lit.fields {
8408
        let case ast::NodeValue::RecordLitField(fieldArg) = fieldNode.value
8409
            else panic "resolveRecordLit: expected field node value";
8410
        let label = fieldArg.label
8411
            else panic "resolveRecordLit: expected labeled field";
8412
        let fieldName = try nodeName(self, label);
8413
        let expected = recordType.fields[idx];
8414
        let expectedName = expected.name else panic;
8415
8416
        if fieldName <> expectedName {
8417
            throw emitError(self, fieldNode, ErrorKind::RecordFieldOutOfOrder {
8418
                field: fieldName,
8419
                prev: expectedName,
8420
            });
8421
        }
8422
        setRecordFieldIndex(self, fieldNode, idx);
8423
        try checkAssignable(self, fieldArg.value, expected.fieldType);
8424
        setNodeType(self, fieldNode, expected.fieldType);
8425
    }
8426
    return setNodeType(self, node, resultType);
8427
}
8428
8429
/// Analyze an anonymous record literal, checking fields against the hint type.
8430
fn resolveAnonRecordLit(self: *mut Resolver, node: *ast::Node, lit: ast::RecordLit, hint: Type) -> Type
8431
    throws (ResolveError)
8432
{
8433
    // Unwrap optional hint to get the inner record type.
8434
    let mut innerHint = hint;
8435
    if let case Type::Optional(inner) = hint {
8436
        set innerHint = *inner;
8437
    }
8438
    let mut hintInfo: ?RecordType = nil;
8439
    if let case Type::Nominal(info) = innerHint {
8440
        try ensureNominalResolved(self, info, node);
8441
        if let case NominalType::Record(s) = *info {
8442
            set hintInfo = s;
8443
        }
8444
    }
8445
    let targetInfo = hintInfo else {
8446
        throw emitError(self, node, ErrorKind::CannotInferType);
8447
    };
8448
8449
    // Check field count.
8450
    if lit.fields.len <> targetInfo.fields.len {
8451
        if lit.fields.len < targetInfo.fields.len {
8452
            let missingName = targetInfo.fields[lit.fields.len].name else panic;
8453
            throw emitError(self, node, ErrorKind::RecordFieldMissing(missingName));
8454
        } else {
8455
            throw emitError(self, node, ErrorKind::RecordFieldCountMismatch(CountMismatch {
8456
                expected: targetInfo.fields.len as u32,
8457
                actual: lit.fields.len,
8458
            }));
8459
        }
8460
    }
8461
8462
    // Fields must be in declaration order.
8463
    for fieldNode, idx in lit.fields {
8464
        let case ast::NodeValue::RecordLitField(fieldArg) = fieldNode.value
8465
            else panic "resolveAnonRecordLit: expected field node value";
8466
        let label = fieldArg.label
8467
            else panic "resolveAnonRecordLit: expected labeled field";
8468
        let fieldName = try nodeName(self, label);
8469
        let expected = targetInfo.fields[idx];
8470
        let expectedName = expected.name else panic;
8471
8472
        if fieldName <> expectedName {
8473
            throw emitError(self, fieldNode, ErrorKind::RecordFieldOutOfOrder {
8474
                field: fieldName,
8475
                prev: expectedName,
8476
            });
8477
        }
8478
        setRecordFieldIndex(self, fieldNode, idx);
8479
        let fieldType = try visit(self, fieldArg.value, expected.fieldType);
8480
8481
        try expectAssignable(self, expected.fieldType, fieldType, fieldArg.value);
8482
        setNodeType(self, fieldNode, fieldType);
8483
    }
8484
    return setNodeType(self, node, innerHint);
8485
}
8486
8487
/// Analyze an array literal expression.
8488
fn resolveArrayLit(self: *mut Resolver, node: *ast::Node, items: *mut [*ast::Node], hint: Type) -> Type
8489
    throws (ResolveError)
8490
{
8491
    let length = items.len;
8492
    let mut expectedTy: Type = Type::Unknown;
8493
8494
    if let case Type::Array(ary) = hint {
8495
        set expectedTy = *ary.item;
8496
    } else if let case Type::Optional(inner) = hint {
8497
        if let case Type::Array(ary) = *inner {
8498
            set expectedTy = *ary.item;
8499
        }
8500
    };
8501
    for itemNode in items {
8502
        let itemTy = try visit(self, itemNode, expectedTy);
8503
        assert itemTy <> Type::Unknown;
8504
8505
        // Set the expected type to the first type we encounter.
8506
        if expectedTy == Type::Unknown {
8507
            set expectedTy = itemTy;
8508
        } else {
8509
            try expectAssignable(self, expectedTy, itemTy, itemNode);
8510
        }
8511
    }
8512
    if expectedTy == Type::Unknown {
8513
        throw emitError(self, node, ErrorKind::CannotInferType);
8514
    };
8515
    let arrayTy = Type::Array(ArrayType { item: allocType(self, expectedTy), length });
8516
    return setNodeType(self, node, arrayTy);
8517
}
8518
8519
/// Analyze an array repeat literal expression.
8520
fn resolveArrayRepeat(self: *mut Resolver, node: *ast::Node, lit: ast::ArrayRepeatLit, hint: Type) -> Type
8521
    throws (ResolveError)
8522
{
8523
    let mut itemHint = hint;
8524
    if let case Type::Array(ary) = hint {
8525
        set itemHint = *ary.item;
8526
    } else if let case Type::GenericArray { item, .. } = hint {
8527
        set itemHint = *item;
8528
    } else if let case Type::Optional(inner) = hint {
8529
        if let case Type::Array(ary) = *inner {
8530
            set itemHint = *ary.item;
8531
        }
8532
    }
8533
    let valueTy = try visit(self, lit.item, itemHint);
8534
    let _ = try checkNumeric(self, lit.count);
8535
    let mut arrayTy: Type = undefined;
8536
    if let value = constValueEntry(self, lit.count) {
8537
        if not validateConstIntRange(value, Type::U32) {
8538
            throw emitError(self, lit.count, ErrorKind::NumericLiteralOverflow);
8539
        }
8540
        let case ConstValue::Int(int) = value
8541
            else throw emitError(self, lit.count, ErrorKind::ConstExprRequired);
8542
        set arrayTy = Type::Array(ArrayType {
8543
            item: allocType(self, valueTy),
8544
            length: int.magnitude as u32,
8545
        });
8546
    } else if isConstExpr(self, lit.count) and
8547
              containsGenericConstExpr(self, lit.count)
8548
    {
8549
        set arrayTy = Type::GenericArray {
8550
            item: allocType(self, valueTy),
8551
            length: lit.count,
8552
        };
8553
    } else {
8554
        throw emitError(self, lit.count, ErrorKind::ConstExprRequired);
8555
    }
8556
    return setNodeType(self, node, arrayTy);
8557
}
8558
8559
/// Resolve union variant access.
8560
fn resolveUnionVariantAccess(
8561
    self: *mut Resolver,
8562
    node: *ast::Node,
8563
    access: ast::Access,
8564
    unionType: UnionType,
8565
    variantName: *[u8]
8566
) -> *mut Symbol throws (ResolveError) {
8567
    // Look up the variant in the union's nominal type.
8568
    for i in 0..unionType.variants.len {
8569
        let variant = &unionType.variants[i];
8570
        if variant.name == variantName {
8571
            let case SymbolData::Variant { ordinal, index, .. } = variant.symbol.data
8572
                else panic "resolveUnionVariantAccess: expected variant symbol";
8573
8574
            // Associate the variant symbol with the child node.
8575
            setNodeSymbol(self, access.child, variant.symbol);
8576
            setNodeSymbol(self, node, variant.symbol);
8577
8578
            // Store the variant index for the lowerer.
8579
            setVariantInfo(self, node, ordinal, index);
8580
8581
            return variant.symbol;
8582
        }
8583
    }
8584
    throw emitError(self, access.child, ErrorKind::UnresolvedSymbol(variantName));
8585
}
8586
8587
/// Analyze a scope access expression.
8588
fn resolveScopeAccess(self: *mut Resolver, node: *ast::Node, access: ast::Access) -> Type
8589
    throws (ResolveError)
8590
{
8591
    let sym = try resolveAccess(self, node, access, self.scope);
8592
    let mut ty: Type = undefined;
8593
8594
    match sym.data {
8595
        case SymbolData::Value { type, .. } => {
8596
            if isGenericDeclaration(sym.node) {
8597
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
8598
            }
8599
            setNodeSymbol(self, node, sym);
8600
            set ty = type;
8601
        }
8602
        case SymbolData::Constant { type, value } => {
8603
            // Propagate the constant value.
8604
            if let val = value {
8605
                setNodeConstValue(self, node, val);
8606
            }
8607
            setNodeSymbol(self, node, sym);
8608
            set ty = type;
8609
        }
8610
        case SymbolData::Type(t) => {
8611
            if isGenericDeclaration(sym.node) {
8612
                throw emitError(self, node, ErrorKind::GenericArgumentsRequired);
8613
            }
8614
            setNodeSymbol(self, node, sym);
8615
            set ty = Type::Nominal(t);
8616
        }
8617
        case SymbolData::TypeParameter(param) => {
8618
            set *param.used = true;
8619
            setNodeSymbol(self, node, sym);
8620
            set ty = Type::Parameter(param);
8621
        }
8622
        case SymbolData::ConstParameter(param) => {
8623
            set *param.used = true;
8624
            setNodeSymbol(self, node, sym);
8625
            let constType = param.constType
8626
                else throw emitError(self, node, ErrorKind::Internal);
8627
            set ty = *constType;
8628
        }
8629
        case SymbolData::Variant { index, .. } => {
8630
            let ty = typeFor(self, node)
8631
                else throw emitError(self, node, ErrorKind::Internal);
8632
            // For unions without payload, store the variant index as a constant.
8633
            if isVoidUnion(ty) {
8634
                setNodeConstValue(self, node, ConstValue::Int(ConstInt {
8635
                    magnitude: index as u64,
8636
                    bits: 32,
8637
                    signed: false,
8638
                    negative: false,
8639
                }));
8640
            }
8641
            return setNodeType(self, node, ty);
8642
        }
8643
        case SymbolData::Module { .. } => {
8644
            throw emitError(self, node, ErrorKind::UnexpectedModuleName);
8645
        }
8646
        case SymbolData::Trait(_) => { // Trait names are not values.
8647
            throw emitError(self, node, ErrorKind::UnexpectedTraitName);
8648
        }
8649
    }
8650
    return setNodeType(self, node, ty);
8651
}
8652
8653
/// A uniquely selected method exposed by a generic parameter bound.
8654
record GenericBoundMethod {
8655
    traitInfo: *TraitType,
8656
    method: *TraitMethod,
8657
}
8658
8659
/// Find one bound method, rejecting ambiguous unqualified selections.
8660
fn findGenericBoundMethod(
8661
    self: *mut Resolver,
8662
    node: *ast::Node,
8663
    param: *GenericParamType,
8664
    name: *[u8],
8665
) -> GenericBoundMethod throws (ResolveError) {
8666
    let mut found: ?GenericBoundMethod = nil;
8667
    for bound in param.bounds {
8668
        if let method = findTraitMethod(bound, name) {
8669
            if found <> nil {
8670
                throw emitError(self, node, ErrorKind::GenericBoundAmbiguous(name));
8671
            }
8672
            set found = GenericBoundMethod { traitInfo: bound, method };
8673
        }
8674
    }
8675
    let result = found else throw emitError(
8676
        self, node, ErrorKind::RecordFieldUnknown(name)
8677
    );
8678
    return result;
8679
}
8680
8681
/// Analyze a field access expression.
8682
fn resolveFieldAccess(self: *mut Resolver, node: *ast::Node, access: ast::Access) -> Type
8683
    throws (ResolveError)
8684
{
8685
    let parentTy = try infer(self, access.parent);
8686
    if isUnsafePointerType(parentTy) {
8687
        try requireUnsafe(self, access.parent);
8688
    }
8689
    let subjectTy = autoDeref(parentTy);
8690
    if let case Type::Slice(slice) = subjectTy {
8691
        let fieldNode = access.child;
8692
        let fieldName = try nodeName(self, fieldNode);
8693
        if mem::eq(fieldName, PTR_FIELD) {
8694
            setRecordFieldIndex(self, fieldNode, 0);
8695
            return setNodeType(
8696
                self,
8697
                node,
8698
                Type::Pointer(PointerType {
8699
                    class: slice.class,
8700
                    target: slice.item,
8701
                    mutable: slice.mutable,
8702
                }),
8703
            );
8704
        }
8705
        if mem::eq(fieldName, LEN_FIELD) {
8706
            setRecordFieldIndex(self, fieldNode, 1);
8707
            return setNodeType(self, node, Type::U32);
8708
        }
8709
        if mem::eq(fieldName, CAP_FIELD) {
8710
            setRecordFieldIndex(self, fieldNode, 2);
8711
            return setNodeType(self, node, Type::U32);
8712
        }
8713
        throw emitError(self, node, ErrorKind::SliceFieldUnknown(fieldName));
8714
    }
8715
    if let case Type::TraitObject(traitObject) = subjectTy {
8716
        let fieldName = try nodeName(self, access.child);
8717
        let method = findTraitMethod(traitObject.traitInfo, fieldName)
8718
            else throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
8719
        return setNodeType(self, node, Type::Fn(method.fnType));
8720
    }
8721
8722
    match subjectTy {
8723
        case Type::Parameter(param) if param.bounds.len > 0 => {
8724
            let fieldName = try nodeName(self, access.child);
8725
            let selected = try findGenericBoundMethod(
8726
                self, access.child, param, fieldName
8727
            );
8728
            let selfParam: [*GenericParamType; 1] = [selected.method.owner.selfType];
8729
            let selfArg: [*Type; 1] = [allocType(self, Type::Parameter(param))];
8730
            let sub = Substitution {
8731
                params: &selfParam[..],
8732
                args: &selfArg[..],
8733
            };
8734
            let methodType = try substituteType(
8735
                self, Type::Fn(selected.method.fnType), &sub, node
8736
            );
8737
            return setNodeType(self, node, methodType);
8738
        }
8739
        case Type::GenericDataApply(application) => {
8740
            let template = genericTemplateFor(self, application.template)
8741
                else throw emitError(self, node, ErrorKind::Internal);
8742
            let case ast::NodeValue::RecordDecl(decl) = application.template.node.value
8743
                else throw emitError(self, access.parent, ErrorKind::ExpectedRecord);
8744
            let fieldName = try nodeName(self, access.child);
8745
            for fieldNode, index in decl.fields {
8746
                let case ast::NodeValue::RecordField { field: maybeField, .. } =
8747
                    fieldNode.value
8748
                    else throw emitError(self, node, ErrorKind::Internal);
8749
                let fieldNodeName = maybeField
8750
                    else throw emitError(self, fieldNode, ErrorKind::Internal);
8751
                let candidate = try nodeName(self, fieldNodeName);
8752
                if mem::eq(candidate, fieldName) {
8753
                    let sub = Substitution {
8754
                        params: template.params,
8755
                        args: application.args,
8756
                    };
8757
                    let fieldType = try substituteType(
8758
                        self, *template.members[index], &sub, node
8759
                    );
8760
                    setRecordFieldIndex(self, access.child, index);
8761
                    return setNodeType(self, node, fieldType);
8762
                }
8763
            }
8764
            throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
8765
        }
8766
        case Type::Nominal(NominalType::Record(recordType)) => {
8767
            let fieldNode = access.child;
8768
            let fieldName = try nodeName(self, fieldNode);
8769
            if let fieldIndex = findRecordField(&recordType, fieldName) {
8770
                let fieldTy = recordType.fields[fieldIndex].fieldType;
8771
                setRecordFieldIndex(self, fieldNode, fieldIndex);
8772
                return setNodeType(self, node, fieldTy);
8773
            }
8774
            // Not a field: check for a standalone method.
8775
            if let method = findMethod(self, subjectTy, fieldName) {
8776
                return setNodeType(self, node, Type::Fn(method.fnType));
8777
            }
8778
            throw emitError(self, node, ErrorKind::RecordFieldUnknown(fieldName));
8779
        }
8780
        case Type::Array(arrayInfo) => {
8781
            let fieldNode = access.child;
8782
            let fieldName = try nodeName(self, fieldNode);
8783
8784
            if mem::eq(fieldName, LEN_FIELD) {
8785
                let lengthConst = constInt(arrayInfo.length as u64, 32, false, false);
8786
                setNodeConstValue(self, node, lengthConst);
8787
8788
                return setNodeType(self, node, Type::U32);
8789
            }
8790
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
8791
        }
8792
        case Type::GenericArray { .. } => {
8793
            let fieldName = try nodeName(self, access.child);
8794
            if mem::eq(fieldName, LEN_FIELD) {
8795
                return setNodeType(self, node, Type::U32);
8796
            }
8797
            throw emitError(self, node, ErrorKind::ArrayFieldUnknown(fieldName));
8798
        }
8799
        else => {
8800
            // Check for standalone methods on any nominal type (e.g. unions).
8801
            if let case Type::Nominal(_) = subjectTy {
8802
                let fieldName = try nodeName(self, access.child);
8803
                if let method = findMethod(self, subjectTy, fieldName) {
8804
                    return setNodeType(self, node, Type::Fn(method.fnType));
8805
                }
8806
            }
8807
            throw emitError(self, access.parent, ErrorKind::ExpectedRecord);
8808
        }
8809
    }
8810
}
8811
8812
/// Determine whether an expression can yield a mutable location for borrowing.
8813
fn canBorrowMutFrom(self: *mut Resolver, node: *ast::Node) -> bool
8814
    throws (ResolveError)
8815
{
8816
    match node.value {
8817
        case ast::NodeValue::Ident(name) => {
8818
            let sym = findValueSymbol(self.scope, name)
8819
                else return false;
8820
            let case SymbolData::Value { mutable, .. } = sym.data
8821
                else return false;
8822
            // Check if the binding itself is mutable, or if it's a mutable pointer.
8823
            if mutable {
8824
                return true;
8825
            }
8826
            // Check if the type is a mutable pointer or slice.
8827
            let ty = typeFor(self, node) else return false;
8828
            if let case Type::Pointer(pointer) = ty {
8829
                return pointer.mutable;
8830
            }
8831
            if let case Type::Slice(slice) = ty {
8832
                return slice.mutable;
8833
            }
8834
            return false;
8835
        }
8836
        case ast::NodeValue::FieldAccess(access) => {
8837
            let _ = try infer(self, access.parent);
8838
            return try canBorrowMutFrom(self, access.parent);
8839
        }
8840
        case ast::NodeValue::ScopeAccess(_) => {
8841
            // Module-qualified access to a top-level symbol. A `static`
8842
            // binds as a mutable value; a `constant` does not.
8843
            let _ = try infer(self, node);
8844
            let sym = nodeData(self, node).sym
8845
                else return false;
8846
8847
            if let case SymbolData::Value { mutable, .. } = sym.data {
8848
                return mutable;
8849
            }
8850
            return false;
8851
        }
8852
        case ast::NodeValue::Subscript { container, .. } => {
8853
            let containerTy = try infer(self, container);
8854
            // Subscript auto-derefs pointers, so check the actual indexed type.
8855
            let subjectTy = autoDeref(containerTy);
8856
8857
            if let case Type::Slice(slice) = subjectTy {
8858
                return slice.mutable;
8859
            }
8860
            if let case Type::Array(_) = subjectTy {
8861
                return try canBorrowMutFrom(self, container);
8862
            }
8863
            return false;
8864
        }
8865
        case ast::NodeValue::ArrayLit(_),
8866
             ast::NodeValue::ArrayRepeatLit(_) =>
8867
        {
8868
            return true;
8869
        }
8870
        case ast::NodeValue::Call(_) => {
8871
            // A call returning `*mut T` (or `&mut [T]`) yields a
8872
            // mutable place. Non-pointer returns cannot be mutably borrowed.
8873
            let ty = try infer(self, node);
8874
            if let case Type::Pointer(pointer) = ty {
8875
                return pointer.mutable;
8876
            }
8877
            if let case Type::Slice(slice) = ty {
8878
                return slice.mutable;
8879
            }
8880
            return false;
8881
        }
8882
        case ast::NodeValue::Deref(inner) => {
8883
            let innerTy = try infer(self, inner);
8884
8885
            if let case Type::Pointer(pointer) = innerTy {
8886
                return pointer.mutable;
8887
            }
8888
            if let case Type::Slice(slice) = innerTy {
8889
                return slice.mutable;
8890
            }
8891
            // Record deref: mutability depends on the inner binding.
8892
            if let case Type::Nominal(NominalType::Record(recInfo)) = innerTy {
8893
                if not recInfo.labeled and recInfo.fields.len == 1 {
8894
                    return try canBorrowMutFrom(self, inner);
8895
                }
8896
            }
8897
            return false;
8898
        }
8899
        else => {
8900
            return false;
8901
        }
8902
    }
8903
}
8904
8905
/// Analyze an address-of expression.
8906
fn resolveAddressOf(self: *mut Resolver, node: *ast::Node, addr: ast::AddressOf, hint: Type) -> Type
8907
    throws (ResolveError)
8908
{
8909
    // Linear source treats every address expression as a call-scoped reference.
8910
    // Legacy packages keep their historical owning-address inference.
8911
    let class = types::PointerClass::Ref
8912
        if self.linearEnabled or isRefType(hint)
8913
        else types::PointerClass::Owned;
8914
    if addr.mutable {
8915
        if not try canBorrowMutFrom(self, addr.target) {
8916
            throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
8917
        }
8918
    }
8919
    if let case ast::NodeValue::Subscript { container, index } = addr.target.value {
8920
        if let case ast::NodeValue::Range(range) = index.value {
8921
            let containerTy = try infer(self, container);
8922
            let subjectTy = autoDeref(containerTy);
8923
8924
            try checkSliceRangeIndices(self, range);
8925
8926
            let mut item: *Type = undefined;
8927
            let mut capacity: ?u32 = nil;
8928
8929
            if let case Type::Slice(slice) = subjectTy {
8930
                if addr.mutable and not slice.mutable {
8931
                    throw emitError(self, addr.target, ErrorKind::ImmutableBinding);
8932
                }
8933
                set item = slice.item;
8934
            } else {
8935
                match subjectTy {
8936
                    case Type::Array(arrayInfo) => {
8937
                        try validateArraySliceBounds(self, range, arrayInfo.length, node);
8938
                        set item = arrayInfo.item;
8939
                        set capacity = arrayInfo.length;
8940
                    }
8941
                    else => {
8942
                        throw emitError(self, container, ErrorKind::ExpectedIndexable);
8943
                    }
8944
                }
8945
            }
8946
            let sliceTy = Type::Slice(SliceType {
8947
                class,
8948
                item,
8949
                mutable: addr.mutable,
8950
            });
8951
            let alloc = allocType(self, sliceTy);
8952
            setSliceRangeInfo(self, node, SliceRangeInfo {
8953
                itemType: item,
8954
                mutable: addr.mutable,
8955
                capacity,
8956
            });
8957
            setNodeType(self, addr.target, *alloc);
8958
            return setNodeType(self, node, *alloc);
8959
        }
8960
    }
8961
    // Derive a hint for the target type from the slice hint.
8962
    let mut targetHint: Type = Type::Unknown;
8963
    if let case Type::Slice(slice) = hint {
8964
        set targetHint = Type::Array(ArrayType { item: slice.item, length: 0 });
8965
    }
8966
    let targetTy = try visit(self, addr.target, targetHint);
8967
8968
    // Mark local variable symbols as address-taken so the lowerer
8969
    // allocates a stack slot eagerly.
8970
    if let case ast::NodeValue::Ident(name) = addr.target.value {
8971
        if let sym = findValueSymbol(self.scope, name) {
8972
            match &mut sym.data {
8973
                case SymbolData::Value { addressTaken, .. } => {
8974
                    set *addressTaken = true;
8975
                }
8976
                else => {}
8977
            }
8978
        }
8979
    }
8980
8981
    if let case Type::Array(arrayInfo) = targetTy {
8982
        match addr.target.value {
8983
            case ast::NodeValue::ArrayLit(_),
8984
                 ast::NodeValue::ArrayRepeatLit(_) =>
8985
            {
8986
                let sliceTy = Type::Slice(SliceType {
8987
                    class,
8988
                    item: arrayInfo.item,
8989
                    mutable: addr.mutable,
8990
                });
8991
                return setNodeType(self, node, *allocType(self, sliceTy));
8992
            }
8993
            else => {}
8994
        }
8995
    }
8996
    let pointerTy = Type::Pointer(PointerType {
8997
        class,
8998
        target: allocType(self, targetTy),
8999
        mutable: addr.mutable,
9000
    });
9001
    return setNodeType(self, node, pointerTy);
9002
}
9003
9004
/// Analyze a dereference expression.
9005
fn resolveDeref(self: *mut Resolver, node: *ast::Node, targetNode: *ast::Node, hint: Type) -> Type
9006
    throws (ResolveError)
9007
{
9008
    let operandTy = try visit(self, targetNode, hint);
9009
    if let case Type::Pointer(pointer) = operandTy {
9010
        if pointer.class == types::PointerClass::Unsafe {
9011
            try requireUnsafe(self, targetNode);
9012
        }
9013
        // Disallow dereferencing opaque pointers.
9014
        if *pointer.target == Type::Opaque {
9015
            throw emitError(self, targetNode, ErrorKind::OpaqueTypeDeref);
9016
        }
9017
        return setNodeType(self, node, *pointer.target);
9018
    }
9019
    // Auto-deref for single-field unlabeled records.
9020
    if let case Type::Nominal(NominalType::Record(recInfo)) = operandTy {
9021
        if not recInfo.labeled and recInfo.fields.len == 1 {
9022
            let fieldTy = recInfo.fields[0].fieldType;
9023
            setRecordFieldIndex(self, node, 0);
9024
            return setNodeType(self, node, fieldTy);
9025
        }
9026
    }
9027
    throw emitError(self, targetNode, ErrorKind::ExpectedPointer);
9028
}
9029
9030
/// Check if a type is a pointer to opaque.
9031
fn isOpaquePointer(ty: Type) -> bool {
9032
    if let case Type::Pointer(pointer) = ty {
9033
        return *pointer.target == Type::Opaque;
9034
    }
9035
    return false;
9036
}
9037
9038
/// Check if a type is an opaque slice.
9039
fn isOpaqueSlice(ty: Type) -> bool {
9040
    if let case Type::Slice(slice) = ty {
9041
        return *slice.item == Type::Opaque;
9042
    }
9043
    return false;
9044
}
9045
9046
/// Check if an `as` cast between two types is valid.
9047
fn isValidCast(source: Type, target: Type) -> bool {
9048
    // Allow identity casts.
9049
    if source == target {
9050
        return true;
9051
    }
9052
    // Allow numeric to numeric.
9053
    if isNumericType(source) and isNumericType(target) {
9054
        return true;
9055
    }
9056
    // Allow `void` union to numeric.
9057
    // TODO: Check that variant index fits in target type.
9058
    if isVoidUnion(source) and isNumericType(target) {
9059
        return true;
9060
    }
9061
    // Allow address to numeric.
9062
    if let case Type::Slice(_) = source {
9063
        // Disallow slice to numeric; slices are fat pointers.
9064
    } else if isAddressType(source) and isNumericType(target) {
9065
        return true;
9066
    }
9067
    // Allow pointer casts if one side is `*opaque` or target types are castable.
9068
    if let case Type::Pointer(sourcePointer) = source {
9069
        if let case Type::Pointer(targetPointer) = target {
9070
            if sourcePointer.class <> targetPointer.class {
9071
                return false;
9072
            }
9073
            if targetPointer.mutable and not sourcePointer.mutable {
9074
                return false;
9075
            }
9076
            if isOpaquePointer(source) or isOpaquePointer(target) {
9077
                return true;
9078
            }
9079
            return isValidCast(*sourcePointer.target, *targetPointer.target);
9080
        }
9081
    }
9082
    // Allow slice casts if one side is `*[opaque]`, target is `*[u8]`,
9083
    // or element types are castable.
9084
    if let case Type::Slice(sourceSlice) = source {
9085
        if let case Type::Slice(targetSlice) = target {
9086
            if sourceSlice.class <> targetSlice.class {
9087
                return false;
9088
            }
9089
            if targetSlice.mutable and not sourceSlice.mutable {
9090
                return false;
9091
            }
9092
            if isOpaqueSlice(source) or isOpaqueSlice(target) {
9093
                return true;
9094
            }
9095
            if *targetSlice.item == Type::U8 {
9096
                return true;
9097
            }
9098
            return isValidCast(*sourceSlice.item, *targetSlice.item);
9099
        }
9100
    }
9101
    return false;
9102
}
9103
9104
/// Analyze an `as` cast expression.
9105
fn resolveAs(self: *mut Resolver, node: *ast::Node, expr: ast::As) -> Type
9106
    throws (ResolveError)
9107
{
9108
    let targetTy = try infer(self, expr.type);
9109
    let sourceTy = try visit(self, expr.value, targetTy);
9110
    if isUnsafePointerType(sourceTy) or isUnsafePointerType(targetTy) {
9111
        try requireUnsafe(self, node);
9112
    }
9113
9114
    assert sourceTy <> Type::Unknown;
9115
    assert targetTy <> Type::Unknown;
9116
9117
    let mut valid = isValidCast(sourceTy, targetTy);
9118
    if let case Type::Pointer(sourcePointer) = sourceTy {
9119
        if let case Type::Pointer(targetPointer) = targetTy {
9120
            if sourcePointer.class == types::PointerClass::Ref and
9121
               targetPointer.class == types::PointerClass::Unsafe and
9122
               (not targetPointer.mutable or sourcePointer.mutable) and
9123
               isValidCast(*sourcePointer.target, *targetPointer.target)
9124
            {
9125
                set valid = true;
9126
            }
9127
        }
9128
    }
9129
    if let case Type::Slice(sourceSlice) = sourceTy {
9130
        if let case Type::Slice(targetSlice) = targetTy {
9131
            if sourceSlice.class == types::PointerClass::Ref and
9132
               targetSlice.class == types::PointerClass::Unsafe and
9133
               (not targetSlice.mutable or sourceSlice.mutable) and
9134
               isValidCast(*sourceSlice.item, *targetSlice.item)
9135
            {
9136
                set valid = true;
9137
            }
9138
        }
9139
    }
9140
    if valid {
9141
        // Propagate the constant value after applying the cast's target-width
9142
        // truncation and signed interpretation.
9143
        if let value = constValueEntry(self, expr.value) {
9144
            if let case ConstValue::Int(i) = value {
9145
                setNodeConstValue(self, node, castConstInt(i, targetTy));
9146
            }
9147
        }
9148
        return setNodeType(self, node, targetTy);
9149
    }
9150
    throw emitError(self, node, ErrorKind::InvalidAsCast(InvalidAsCast {
9151
        from: sourceTy,
9152
        to: targetTy,
9153
    }));
9154
}
9155
9156
/// Analyze a range expression.
9157
fn resolveRange(self: *mut Resolver, node: *ast::Node, range: ast::Range) -> Type
9158
    throws (ResolveError)
9159
{
9160
    let mut start: ?*Type = nil;
9161
    let mut end: ?*Type = nil;
9162
9163
    if let s = range.start {
9164
        let startTy = try checkNumeric(self, s);
9165
9166
        if let e = range.end {
9167
            let endTy = try checkNumeric(self, e);
9168
            let mut resolvedTy = startTy;
9169
9170
            // Infer unsuffixed integer literals from the opposite bound.
9171
            if startTy == Type::Int and endTy <> Type::Int {
9172
                let _ = try checkAssignable(self, s, endTy);
9173
                set resolvedTy = endTy;
9174
            } else if endTy == Type::Int and startTy <> Type::Int {
9175
                let _ = try checkAssignable(self, e, startTy);
9176
                set resolvedTy = startTy;
9177
            } else {
9178
                let _ = try checkAssignable(self, e, startTy);
9179
            }
9180
            set start = allocType(self, resolvedTy);
9181
            set end = allocType(self, resolvedTy);
9182
        } else {
9183
            set start = allocType(self, startTy);
9184
        }
9185
    } else if let e = range.end {
9186
        set end = allocType(self, try checkNumeric(self, e));
9187
    }
9188
    return setNodeType(self, node, Type::Range { start, end });
9189
}
9190
9191
/// Analyze a `try` expression and its handlers.
9192
/// The `expected` type is used to determine if the value is discarded (`Void`)
9193
/// or if the catch expression needs type checking.
9194
fn resolveTry(self: *mut Resolver, node: *ast::Node, tryExpr: ast::Try, hint: Type) -> Type
9195
    throws (ResolveError)
9196
{
9197
    let call = tryExpr.expr;
9198
    let case ast::NodeValue::Call(callExpr) = call.value
9199
        else throw emitError(self, call, ErrorKind::TryNonThrowing);
9200
    let resultTy = try resolveCall(
9201
        self, call, callExpr, CallCtx::Try, hint
9202
    );
9203
9204
    // TODO: It's annoying that we need to re-fetch the function type after
9205
    // analyzing the call.
9206
    let calleeTy = typeFor(self, callExpr.callee)
9207
        else return setNodeType(self, node, resultTy);
9208
    let case Type::Fn(calleeInfo) = calleeTy
9209
        else throw emitError(self, callExpr.callee, ErrorKind::TryNonThrowing);
9210
9211
    if calleeInfo.throwList.len == 0 {
9212
        throw emitError(self, callExpr.callee, ErrorKind::TryNonThrowing);
9213
    }
9214
    // If we're not catching the error, nor panicking on error, nor returning
9215
    // optional, then the current function must be able to propagate it.
9216
    let mut tryResultTy = resultTy;
9217
    if tryExpr.returnsOptional {
9218
        // `try?` converts errors to `nil` and wraps the result in an optional.
9219
        if let case Type::Optional(_) = resultTy {
9220
            // Already optional, no wrapping needed.
9221
        } else {
9222
            set tryResultTy = Type::Optional(allocType(self, resultTy));
9223
        }
9224
    } else if tryExpr.catches.len > 0 {
9225
        // `try ... catch` -- one or more catch clauses.
9226
        set tryResultTy = try resolveTryCatches(self, node, tryExpr.catches, calleeInfo, resultTy, hint);
9227
    } else if not tryExpr.shouldPanic {
9228
        let fnInfo = self.currentFn
9229
            else throw emitError(self, node, ErrorKind::TryRequiresThrows);
9230
        if fnInfo.throwList.len == 0 {
9231
            throw emitError(self, node, ErrorKind::TryRequiresThrows);
9232
        }
9233
        // Check that *all* thrown errors of the callee can be propagated by
9234
        // the caller.
9235
        for throwTy in calleeInfo.throwList {
9236
            let mut found = false;
9237
9238
            for callerThrowTy in fnInfo.throwList {
9239
                if callerThrowTy == throwTy {
9240
                    set found = true;
9241
                    break;
9242
                }
9243
            }
9244
            if not found {
9245
                throw emitError(self, node, ErrorKind::TryIncompatibleError);
9246
            }
9247
        }
9248
    }
9249
    return setNodeType(self, node, tryResultTy);
9250
}
9251
9252
/// Check that a `catch` body is assignable to the expected result type, but only
9253
/// in expression context (`hint` is neither `Unknown` nor `Void`).
9254
fn checkCatchBody(self: *mut Resolver, body: *ast::Node, resultTy: Type, hint: Type)
9255
    throws (ResolveError)
9256
{
9257
    if hint <> Type::Unknown and hint <> Type::Void {
9258
        try checkAssignable(self, body, resultTy);
9259
    }
9260
}
9261
9262
/// Resolve catch clauses for a `try ... catch` expression.
9263
///
9264
/// For a single untyped catch (with or without binding), resolves the catch
9265
/// body and returns the result type. Multi-error callees with inferred bindings
9266
/// are rejected; you must use typed catches.
9267
fn resolveTryCatches(
9268
    self: *mut Resolver,
9269
    node: *ast::Node,
9270
    catches: *mut [*ast::Node],
9271
    calleeInfo: *FnType,
9272
    resultTy: Type,
9273
    hint: Type
9274
) -> Type throws (ResolveError) {
9275
    let firstNode = catches[0];
9276
    let case ast::NodeValue::CatchClause(first) = firstNode.value else
9277
        throw emitError(self, node, ErrorKind::UnexpectedNode(firstNode));
9278
9279
    // Typed catches: dispatch to dedicated handler.
9280
    if first.typeNode <> nil {
9281
        return try resolveTypedCatches(self, node, catches, calleeInfo, resultTy, hint);
9282
    }
9283
    // Single untyped catch clause.
9284
    if let binding = first.binding {
9285
        if calleeInfo.throwList.len > 1 {
9286
            throw emitError(self, binding, ErrorKind::TryCatchMultiError);
9287
        }
9288
        enterScope(self, node);
9289
9290
        let errTy = *calleeInfo.throwList[0];
9291
        try bindValueIdent(self, binding, binding, errTy, false, 0, 0);
9292
    }
9293
    try visit(self, first.body, resultTy);
9294
9295
    if let _ = first.binding {
9296
        exitScope(self);
9297
    }
9298
    try checkCatchBody(self, first.body, resultTy, hint);
9299
9300
    return resultTy;
9301
}
9302
9303
/// Resolve typed catch clauses (`catch e as T {..} catch e as S {..}`).
9304
///
9305
/// Validates that each type annotation is in the callee's throw list, that
9306
/// there are no duplicate catch types, and that the clauses are exhaustive.
9307
fn resolveTypedCatches(
9308
    self: *mut Resolver,
9309
    node: *ast::Node,
9310
    catches: *mut [*ast::Node],
9311
    calleeInfo: *FnType,
9312
    resultTy: Type,
9313
    hint: Type
9314
) -> Type throws (ResolveError) {
9315
    // Track which of the callee's throw types have been covered.
9316
    let mut covered: [bool; MAX_FN_THROWS] = [false; MAX_FN_THROWS];
9317
    let mut hasCatchAll = false;
9318
9319
    for clauseNode in catches {
9320
        let case ast::NodeValue::CatchClause(clause) = clauseNode.value else
9321
            throw emitError(self, node, ErrorKind::UnexpectedNode(clauseNode));
9322
9323
        if let typeNode = clause.typeNode {
9324
            // Typed catch clause: validate against callee's throw list.
9325
            let errTy = try infer(self, typeNode);
9326
            let mut foundIdx: ?u32 = nil;
9327
9328
            for throwType, j in calleeInfo.throwList {
9329
                if errTy == *throwType {
9330
                    set foundIdx = j;
9331
                    break;
9332
                }
9333
            }
9334
            let idx = foundIdx else {
9335
                throw emitError(self, typeNode, ErrorKind::TryIncompatibleError);
9336
            };
9337
            if covered[idx] {
9338
                throw emitError(self, typeNode, ErrorKind::TryCatchDuplicateType);
9339
            }
9340
            set covered[idx] = true;
9341
9342
            // Bind the error variable if present.
9343
            if let binding = clause.binding {
9344
                enterScope(self, clauseNode);
9345
                try bindValueIdent(self, binding, binding, errTy, false, 0, 0);
9346
            }
9347
        } else {
9348
            // Catch-all clause with no type annotation or binding.
9349
            set hasCatchAll = true;
9350
        }
9351
        // Resolve the catch body and check assignability.
9352
        try visit(self, clause.body, resultTy);
9353
        // Only typed clauses can have bindings.
9354
        if let _ = clause.binding {
9355
            exitScope(self);
9356
        }
9357
        try checkCatchBody(self, clause.body, resultTy, hint);
9358
    }
9359
9360
    // Check exhaustiveness: all callee error types must be covered.
9361
    if not hasCatchAll {
9362
        for i in 0..calleeInfo.throwList.len {
9363
            if not covered[i] {
9364
                throw emitError(self, node, ErrorKind::TryCatchNonExhaustive);
9365
            }
9366
        }
9367
    }
9368
    return resultTy;
9369
}
9370
9371
/// Analyze a `throw` statement.
9372
fn resolveThrow(self: *mut Resolver, node: *ast::Node, expr: *ast::Node) -> Type
9373
    throws (ResolveError)
9374
{
9375
    let fnInfo = self.currentFn
9376
        else throw emitError(self, node, ErrorKind::ThrowRequiresThrows);
9377
    if fnInfo.throwList.len == 0 {
9378
        throw emitError(self, node, ErrorKind::ThrowRequiresThrows);
9379
    }
9380
    let throwTy = try infer(self, expr);
9381
    for errTy in fnInfo.throwList {
9382
        if let coerce = isAssignable(self, *errTy, throwTy, expr) {
9383
            setNodeCoercion(self, expr, coerce);
9384
            return setNodeType(self, node, Type::Never);
9385
        }
9386
    }
9387
    throw emitError(self, expr, ErrorKind::ThrowIncompatibleError);
9388
}
9389
9390
/// Analyze a `return` statement.
9391
fn resolveReturn(self: *mut Resolver, node: *ast::Node, retVal: ?*ast::Node) -> Type
9392
    throws (ResolveError)
9393
{
9394
    let f = self.currentFn
9395
        else throw emitError(self, node, ErrorKind::UnexpectedReturn);
9396
    let expected = *f.returnType;
9397
9398
    if let val = retVal {
9399
        let _actualTy = try checkAssignable(self, val, expected);
9400
    } else if expected <> Type::Void {
9401
        throw emitTypeMismatch(self, node, TypeMismatch { expected, actual: Type::Void });
9402
    }
9403
    // In throwing functions, return values are wrapped in the success variant.
9404
    if f.throwList.len > 0 {
9405
        setNodeCoercion(self, node, Coercion::ResultWrap);
9406
    }
9407
    return setNodeType(self, node, Type::Never);
9408
}
9409
9410
/// Convert a [`ConstInt`] to its two's-complement bit pattern.
9411
fn constIntToBits(c: ConstInt) -> u64 {
9412
    return (0 - c.magnitude) if c.negative else c.magnitude;
9413
}
9414
9415
/// Convert a [`ConstInt`] to its signed two's-complement representation.
9416
fn constIntToSigned(c: ConstInt) -> i64 {
9417
    return constIntToBits(c) as i64;
9418
}
9419
9420
/// Build a [`ConstInt`] from a signed result, preserving bit width and signedness.
9421
fn constIntFromSigned(value: i64, bits: u8, signed: bool) -> ConstInt {
9422
    if value < 0 {
9423
        // Compute magnitude without signed overflow.
9424
        let uval = value as u64;
9425
        return ConstInt {
9426
            magnitude: 0 - uval,
9427
            bits,
9428
            signed,
9429
            negative: true,
9430
        };
9431
    }
9432
    return ConstInt {
9433
        magnitude: value as u64,
9434
        bits,
9435
        signed,
9436
        negative: false,
9437
    };
9438
}
9439
9440
/// Build a [`ConstInt`] from a two's-complement bit pattern.
9441
fn constIntFromBits(raw: u64, bits: u8, signed: bool) -> ConstInt {
9442
    let mask = parser::U64_MAX if bits == 64 else parser::U64_MAX >> (64 - bits) as u64;
9443
    let truncated = raw & mask;
9444
9445
    if signed {
9446
        let signBit = (mask >> 1) + 1;
9447
        if (truncated & signBit) <> 0 {
9448
            return ConstInt {
9449
                magnitude: (0 - truncated) & mask,
9450
                bits,
9451
                signed,
9452
                negative: true,
9453
            };
9454
        }
9455
    }
9456
    return ConstInt { magnitude: truncated, bits, signed, negative: false };
9457
}
9458
9459
/// Try to fold a binary operation on two integer constants.
9460
/// Returns the resulting constant value if successful.
9461
fn foldIntBinOp(op: ast::BinaryOp, left: ConstInt, right: ConstInt) -> ?ConstValue {
9462
    // Use the wider bit width and propagate signedness.
9463
    let mut bits = left.bits;
9464
    if right.bits > bits {
9465
        set bits = right.bits;
9466
    }
9467
    let signed = left.signed or right.signed;
9468
    let l = constIntToSigned(left);
9469
    let r = constIntToSigned(right);
9470
9471
    match op {
9472
        // Shift counts are masked to the left operand's width, matching
9473
        // the runtime word instructions.
9474
        case ast::BinaryOp::Shl => {
9475
            let raw = constIntToBits(left);
9476
            let shamt = constIntToBits(right) % left.bits as u64;
9477
            return ConstValue::Int(constIntFromBits(raw << shamt, left.bits, left.signed));
9478
        },
9479
        case ast::BinaryOp::Shr => {
9480
            let shamt = constIntToBits(right) % left.bits as u64;
9481
            if left.signed {
9482
                let shifted = constIntToSigned(left) >> shamt as i64;
9483
                return ConstValue::Int(
9484
                    constIntFromBits(shifted as u64, left.bits, true)
9485
                );
9486
            }
9487
            return ConstValue::Int(
9488
                constIntFromBits(left.magnitude >> shamt, left.bits, false)
9489
            );
9490
        },
9491
        case ast::BinaryOp::Eq  => return ConstValue::Bool(l == r),
9492
        case ast::BinaryOp::Ne  => return ConstValue::Bool(l <> r),
9493
        case ast::BinaryOp::Lt =>
9494
            return ConstValue::Bool(l < r if signed else left.magnitude < right.magnitude),
9495
        case ast::BinaryOp::Gt =>
9496
            return ConstValue::Bool(l > r if signed else left.magnitude > right.magnitude),
9497
        case ast::BinaryOp::Lte =>
9498
            return ConstValue::Bool(l <= r if signed else left.magnitude <= right.magnitude),
9499
        case ast::BinaryOp::Gte =>
9500
            return ConstValue::Bool(l >= r if signed else left.magnitude >= right.magnitude),
9501
        case ast::BinaryOp::Add => {
9502
            if not signed {
9503
                return ConstValue::Int(
9504
                    constIntFromBits(left.magnitude + right.magnitude, bits, false)
9505
                );
9506
            }
9507
            return ConstValue::Int(constIntFromSigned(l + r, bits, true));
9508
        },
9509
        case ast::BinaryOp::Sub => {
9510
            if not signed {
9511
                return ConstValue::Int(
9512
                    constIntFromBits(left.magnitude - right.magnitude, bits, false)
9513
                );
9514
            }
9515
            return ConstValue::Int(constIntFromSigned(l - r, bits, true));
9516
        },
9517
        case ast::BinaryOp::Mul => {
9518
            if not signed {
9519
                return ConstValue::Int(
9520
                    constIntFromBits(left.magnitude * right.magnitude, bits, false)
9521
                );
9522
            }
9523
            return ConstValue::Int(constIntFromSigned(l * r, bits, true));
9524
        },
9525
        case ast::BinaryOp::Div => {
9526
            if signed {
9527
                if r == 0 {
9528
                    return nil;
9529
                }
9530
                if l == parser::I64_MIN and r == -1 {
9531
                    return ConstValue::Int(
9532
                        constIntFromBits(parser::I64_MIN as u64, bits, true)
9533
                    );
9534
                }
9535
                return ConstValue::Int(constIntFromSigned(l / r, bits, true));
9536
            }
9537
            if right.magnitude == 0 {
9538
                return nil;
9539
            }
9540
            return constInt(left.magnitude / right.magnitude, bits, false, false);
9541
        },
9542
        case ast::BinaryOp::Mod => {
9543
            if signed {
9544
                if r == 0 {
9545
                    return nil;
9546
                }
9547
                if l == parser::I64_MIN and r == -1 {
9548
                    return ConstValue::Int(
9549
                        constIntFromBits(0, bits, true)
9550
                    );
9551
                }
9552
                return ConstValue::Int(constIntFromSigned(l % r, bits, true));
9553
            }
9554
            if right.magnitude == 0 {
9555
                return nil;
9556
            }
9557
            return constInt(left.magnitude % right.magnitude, bits, false, false);
9558
        },
9559
        case ast::BinaryOp::BitAnd => return ConstValue::Int(
9560
            constIntFromBits(constIntToBits(left) & constIntToBits(right), bits, signed)
9561
        ),
9562
        case ast::BinaryOp::BitOr => return ConstValue::Int(
9563
            constIntFromBits(constIntToBits(left) | constIntToBits(right), bits, signed)
9564
        ),
9565
        case ast::BinaryOp::BitXor => return ConstValue::Int(
9566
            constIntFromBits(constIntToBits(left) ^ constIntToBits(right), bits, signed)
9567
        ),
9568
        else => return nil,
9569
    }
9570
}
9571
9572
/// Try to constant-fold a binary operation on two resolved operands.
9573
/// Only folds when the result type is concrete.
9574
fn tryFoldBinOp(self: *mut Resolver, node: *ast::Node, binop: ast::BinOp, resultTy: Type) {
9575
    let leftVal = constValueEntry(self, binop.left)
9576
        else return;
9577
    let rightVal = constValueEntry(self, binop.right)
9578
        else return;
9579
9580
    // Fold integer binary ops.
9581
    if let case ConstValue::Int(leftInt) = leftVal {
9582
        if let case ConstValue::Int(rightInt) = rightVal {
9583
            if let result = foldIntBinOp(binop.op, leftInt, rightInt) {
9584
                setNodeConstValue(self, node, result);
9585
            }
9586
            return;
9587
        }
9588
    }
9589
9590
    // Fold boolean binary ops.
9591
    if let case ConstValue::Bool(l) = leftVal {
9592
        if let case ConstValue::Bool(r) = rightVal {
9593
            match binop.op {
9594
                case ast::BinaryOp::And => setNodeConstValue(self, node, ConstValue::Bool(l and r)),
9595
                case ast::BinaryOp::Or => setNodeConstValue(self, node, ConstValue::Bool(l or r)),
9596
                case ast::BinaryOp::Eq => setNodeConstValue(self, node, ConstValue::Bool(l == r)),
9597
                case ast::BinaryOp::Ne,
9598
                     ast::BinaryOp::Xor => setNodeConstValue(self, node, ConstValue::Bool(l <> r)),
9599
                else => {}
9600
            }
9601
        }
9602
    }
9603
}
9604
9605
/// Analyze a binary expression.
9606
fn resolveBinOp(self: *mut Resolver, node: *ast::Node, binop: ast::BinOp) -> Type
9607
    throws (ResolveError)
9608
{
9609
    let mut resultTy = Type::Unknown;
9610
9611
    match binop.op {
9612
        case ast::BinaryOp::And,
9613
             ast::BinaryOp::Or,
9614
             ast::BinaryOp::Xor =>
9615
        {
9616
            try checkBoolean(self, binop.left);
9617
            try checkBoolean(self, binop.right);
9618
9619
            set resultTy = Type::Bool;
9620
        },
9621
        case ast::BinaryOp::Eq,
9622
             ast::BinaryOp::Ne =>
9623
        {
9624
            let leftTy = try infer(self, binop.left);
9625
            let rightTy = try visit(self, binop.right, leftTy);
9626
            if isUnsafePointerType(leftTy) or isUnsafePointerType(rightTy) {
9627
                try requireUnsafe(self, node);
9628
            }
9629
9630
            if not isComparable(leftTy, rightTy) {
9631
                throw emitTypeMismatch(self, binop.right, TypeMismatch {
9632
                    expected: leftTy,
9633
                    actual: rightTy,
9634
                });
9635
            }
9636
            // When comparing `T == ?T`, record a coercion on the
9637
            // non-optional side so the lowerer lifts it before comparing.
9638
            // We use the already-optional type from the other side rather than
9639
            // constructing a new optional, so that e.g. `?u8 == 42` coerces
9640
            // `42` to `?u8` (not `?i32`). We also record OptionalLift directly
9641
            // rather than using expectAssignable, because comparisons should
9642
            // allow e.g. `?*mut T == *T` where mutability differs.
9643
            if let case Type::Optional(_) = leftTy {
9644
                if not isOptionalType(rightTy) {
9645
                    setNodeCoercion(self, binop.right, Coercion::OptionalLift(leftTy));
9646
                }
9647
            } else if let case Type::Optional(_) = rightTy {
9648
                setNodeCoercion(self, binop.left, Coercion::OptionalLift(rightTy));
9649
            }
9650
            set resultTy = Type::Bool;
9651
        },
9652
        else => {
9653
            // Check for pointer arithmetic before numeric check.
9654
            if binop.op == ast::BinaryOp::Add or binop.op == ast::BinaryOp::Sub {
9655
                let leftTy = try infer(self, binop.left);
9656
                let rightTy = try visit(self, binop.right, leftTy);
9657
9658
                // Allow arithmetic on owning pointers and unsafe pointers, but
9659
                // never on references.
9660
                if let case Type::Pointer(leftPointer) = leftTy {
9661
                    if *leftPointer.target == Type::Opaque {
9662
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
9663
                    }
9664
                    if leftPointer.class <> types::PointerClass::Ref
9665
                        and isNumericType(rightTy)
9666
                    {
9667
                        if leftPointer.class == types::PointerClass::Unsafe {
9668
                            try requireUnsafe(self, node);
9669
                        }
9670
                        return setNodeType(self, node, leftTy);
9671
                    }
9672
                }
9673
                if let case Type::Pointer(rightPointer) = rightTy {
9674
                    if *rightPointer.target == Type::Opaque {
9675
                        throw emitError(self, node, ErrorKind::OpaquePointerArithmetic);
9676
                    }
9677
                    if binop.op == ast::BinaryOp::Add
9678
                        and rightPointer.class <> types::PointerClass::Ref
9679
                        and isNumericType(leftTy)
9680
                    {
9681
                        if rightPointer.class == types::PointerClass::Unsafe {
9682
                            try requireUnsafe(self, node);
9683
                        }
9684
                        return setNodeType(self, node, rightTy);
9685
                    }
9686
                }
9687
            }
9688
            let leftTy = try checkNumeric(self, binop.left);
9689
            let rightTy = try checkNumeric(self, binop.right);
9690
9691
            let mut operandTy = leftTy;
9692
            if leftTy <> rightTy {
9693
                if leftTy == Type::Int {
9694
                    set operandTy = rightTy;
9695
                } else if rightTy <> Type::Int {
9696
                    throw emitTypeMismatch(self, binop.right, TypeMismatch {
9697
                        expected: leftTy,
9698
                        actual: rightTy,
9699
                    });
9700
                }
9701
            }
9702
9703
            // Ordering comparisons return `bool`, not the operand type.
9704
            match binop.op {
9705
                case ast::BinaryOp::Lt, ast::BinaryOp::Gt,
9706
                     ast::BinaryOp::Lte, ast::BinaryOp::Gte =>
9707
                    set resultTy = Type::Bool,
9708
                else =>
9709
                    set resultTy = operandTy,
9710
            }
9711
9712
        }
9713
    };
9714
    // Try constant folding after both operands are resolved.
9715
    tryFoldBinOp(self, node, binop, resultTy);
9716
9717
    return setNodeType(self, node, resultTy);
9718
}
9719
9720
/// Analyze a unary expression.
9721
fn resolveUnOp(self: *mut Resolver, node: *ast::Node, unop: ast::UnOp) -> Type
9722
    throws (ResolveError)
9723
{
9724
    let mut resultTy = Type::Unknown;
9725
9726
    match unop.op {
9727
        case ast::UnaryOp::Not => {
9728
            set resultTy = try checkBoolean(self, unop.value);
9729
            if let value = constValueEntry(self, unop.value) {
9730
                if let case ConstValue::Bool(val) = value {
9731
                    setNodeConstValue(self, node, ConstValue::Bool(not val));
9732
                }
9733
            }
9734
        },
9735
        case ast::UnaryOp::Neg => {
9736
            // TODO: Check that we're allowed to use `-` here? Should negation
9737
            // only be valid for signed integers?
9738
            set resultTy = try checkNumeric(self, unop.value);
9739
            if let value = constValueEntry(self, unop.value) {
9740
                // Get the constant expression for the value, flip the sign,
9741
                // and store that new expression on the unary op node.
9742
                if let case ConstValue::Int(intVal) = value {
9743
                    setNodeConstValue(
9744
                        self,
9745
                        node,
9746
                        constInt(intVal.magnitude, intVal.bits, true, not intVal.negative)
9747
                    );
9748
                }
9749
            }
9750
        },
9751
        case ast::UnaryOp::BitNot => {
9752
            set resultTy = try checkNumeric(self, unop.value);
9753
            if let value = constValueEntry(self, unop.value) {
9754
                if let case ConstValue::Int(intVal) = value {
9755
                    let signed = constIntToSigned(intVal);
9756
                    let inverted = constIntFromSigned(-(signed + 1), intVal.bits, intVal.signed);
9757
                    setNodeConstValue(self, node, ConstValue::Int(inverted));
9758
                }
9759
            }
9760
        },
9761
    };
9762
    return setNodeType(self, node, resultTy);
9763
}
9764
9765
9766
9767
/// Resolve a type signature node and set its type.
9768
fn inferTypeSig(self: *mut Resolver, node: *ast::Node, sig: ast::TypeSig) -> Type
9769
    throws (ResolveError)
9770
{
9771
    let resolved = try resolveTypeSig(self, node, sig);
9772
9773
    return setNodeType(self, node, resolved);
9774
}
9775
9776
/// Convert a type signature node into a type value.
9777
fn resolveTypeSig(self: *mut Resolver, node: *ast::Node, sig: ast::TypeSig) -> Type
9778
    throws (ResolveError)
9779
{
9780
    match sig {
9781
        case ast::TypeSig::Void => {
9782
            return Type::Void;
9783
        }
9784
        case ast::TypeSig::Opaque => {
9785
            return Type::Opaque;
9786
        }
9787
        case ast::TypeSig::Bool => {
9788
            return Type::Bool;
9789
        }
9790
        case ast::TypeSig::Integer { width, sign } => {
9791
            let u = sign == ast::Signedness::Unsigned;
9792
            match width {
9793
                case 1 => return Type::U8 if u else Type::I8,
9794
                case 2 => return Type::U16 if u else Type::I16,
9795
                case 4 => return Type::U32 if u else Type::I32,
9796
                case 8 => return Type::U64 if u else Type::I64,
9797
                else => {
9798
                    panic "resolveTypeSig: invalid integer width";
9799
                }
9800
            }
9801
        }
9802
        case ast::TypeSig::Array { itemType, length } => {
9803
            let item = try infer(self, itemType);
9804
            let length = try checkSizeInt(self, length);
9805
9806
            return Type::Array(ArrayType { item: allocType(self, item), length });
9807
        }
9808
        case ast::TypeSig::Slice { class, itemType, mutable } => {
9809
            let item = try infer(self, itemType);
9810
            return Type::Slice(SliceType {
9811
                class,
9812
                item: allocType(self, item),
9813
                mutable,
9814
            });
9815
        }
9816
        case ast::TypeSig::Pointer { class, valueType, mutable } => {
9817
            let target = try infer(self, valueType);
9818
            return Type::Pointer(PointerType {
9819
                class,
9820
                target: allocType(self, target),
9821
                mutable,
9822
            });
9823
        }
9824
        case ast::TypeSig::Optional { valueType } => {
9825
            let payload = try infer(self, valueType);
9826
            return Type::Optional(allocType(self, payload));
9827
        }
9828
        case ast::TypeSig::Nominal(name) => {
9829
            if let case ast::NodeValue::Ident(paramName) = name.value {
9830
                if mem::eq(paramName, "Self") {
9831
                    let selfType = self.currentTraitSelf else {
9832
                        throw emitError(
9833
                            self, name, ErrorKind::UnresolvedSymbol(paramName)
9834
                        );
9835
                    };
9836
                    set *selfType.used = true;
9837
                    return Type::Parameter(selfType);
9838
                }
9839
                let sym = findTypeSymbol(self.scope, paramName) else {
9840
                    throw emitError(self, name, ErrorKind::UnresolvedSymbol(paramName));
9841
                };
9842
                match sym.data {
9843
                    case SymbolData::Type(ty) => {
9844
                        if isGenericDeclaration(sym.node) {
9845
                            throw emitError(self, name, ErrorKind::GenericArgumentsRequired);
9846
                        }
9847
                        setNodeSymbol(self, name, sym);
9848
                        return Type::Nominal(ty);
9849
                    }
9850
                    case SymbolData::TypeParameter(param) => {
9851
                        set *param.used = true;
9852
                        setNodeSymbol(self, name, sym);
9853
                        return Type::Parameter(param);
9854
                    }
9855
                    else => throw emitError(self, name, ErrorKind::Internal),
9856
                }
9857
            }
9858
            let ty = try resolveTypeName(self, name);
9859
            return Type::Nominal(ty);
9860
        }
9861
        case ast::TypeSig::Record { fields, labeled } => {
9862
            let recordType = try resolveRecordFields(self, node, fields, labeled);
9863
            let nominalTy = allocNominalType(self, NominalType::Record(recordType));
9864
            return Type::Nominal(nominalTy);
9865
        }
9866
        case ast::TypeSig::Fn(t) => {
9867
            let a = alloc::arenaAllocator(&mut self.arena);
9868
            let mut paramTypes: *mut [*Type] = &mut [];
9869
            let mut throwList: *mut [*Type] = &mut [];
9870
9871
            if t.params.len > MAX_FN_PARAMS {
9872
                throw emitError(self, node, ErrorKind::FnParamOverflow(CountMismatch {
9873
                    expected: MAX_FN_PARAMS,
9874
                    actual: t.params.len,
9875
                }));
9876
            }
9877
            if t.throwList.len > MAX_FN_THROWS {
9878
                throw emitError(self, node, ErrorKind::FnThrowOverflow(CountMismatch {
9879
                    expected: MAX_FN_THROWS,
9880
                    actual: t.throwList.len,
9881
                }));
9882
            }
9883
9884
            for paramNode in t.params {
9885
                let paramTy = try resolveValueType(self, paramNode);
9886
                paramTypes.append(allocType(self, paramTy), a);
9887
            }
9888
            for tyNode in t.throwList {
9889
                let throwTy = try resolveValueType(self, tyNode);
9890
                try ensureStorableType(self, tyNode, throwTy);
9891
                throwList.append(allocType(self, throwTy), a);
9892
            }
9893
            let mut retType = allocType(self, Type::Void);
9894
            if let ret = t.returnType {
9895
                let resolvedRet = try resolveValueType(self, ret);
9896
                try ensureStorableType(self, ret, resolvedRet);
9897
                set retType = allocType(self, resolvedRet);
9898
            }
9899
            let fnType = FnType {
9900
                paramTypes: &paramTypes[..],
9901
                returnType: retType,
9902
                throwList: &throwList[..],
9903
                isUnsafe: false,
9904
                localCount: 0,
9905
            };
9906
            return Type::Fn(allocFnType(self, fnType));
9907
        }
9908
        // Resolve an opaque trait object signature.
9909
        case ast::TypeSig::TraitObject { class, traitName, mutable } => {
9910
            let sym = try resolveNamePath(self, traitName);
9911
            let case SymbolData::Trait(traitInfo) = sym.data
9912
                else throw emitError(self, traitName, ErrorKind::Internal);
9913
            if traitInfo.state == TraitState::Queued {
9914
                let case ast::NodeValue::TraitDecl { supertraits, methods, .. } = sym.node.value
9915
                    else throw emitError(self, traitName, ErrorKind::Internal);
9916
                try resolveTraitBody(self, sym.node, supertraits, methods);
9917
            }
9918
            if not traitInfo.objectSafe {
9919
                throw emitError(self, traitName, ErrorKind::TraitNotObjectSafe);
9920
            }
9921
            setNodeSymbol(self, traitName, sym);
9922
            return Type::TraitObject(TraitObjectType { class, traitInfo, mutable });
9923
        }
9924
    }
9925
}
9926
9927
/// Check if a type can be used for inferrence.
9928
fn isTypeInferrable(type: Type) -> bool {
9929
    if let case Type::Pointer(pointer) = type {
9930
        return isTypeInferrable(*pointer.target);
9931
    }
9932
    match type {
9933
        case Type::Unknown, Type::Nil, Type::Undefined, Type::Int => return false,
9934
        case Type::Array(ary) => return isTypeInferrable(*ary.item),
9935
        case Type::Optional(opt) => return isTypeInferrable(*opt),
9936
        else => return true,
9937
    }
9938
}
9939
9940
/// Analyze a standalone expression by wrapping it in a synthetic function.
9941
export fn resolveExpr(
9942
    self: *mut Resolver, expr: *ast::Node, arena: *mut ast::NodeArena
9943
) -> Diagnostics throws (ResolveError) {
9944
    let a = alloc::arenaAllocator(&mut arena.arena);
9945
    let exprStmt = ast::synthNode(arena, ast::NodeValue::ExprStmt(expr));
9946
    let bodyStmts = ast::nodeSlice(arena, 1).append(exprStmt, a);
9947
    let module = ast::synthFnModule(arena, ANALYZE_EXPR_FN_NAME, bodyStmts);
9948
9949
    let case ast::NodeValue::Block(block) = module.modBody.value
9950
        else panic "resolveExpr: expected block for module body";
9951
    enterScope(self, module.modBody);
9952
    try resolveModuleDecls(self, &block) catch {
9953
        return Diagnostics { errors: self.errors };
9954
    };
9955
    try resolveModuleDefs(self, &block) catch {
9956
        return Diagnostics { errors: self.errors };
9957
    };
9958
    exitScope(self);
9959
9960
    return Diagnostics { errors: self.errors };
9961
}
9962
9963
/// Analyze a parsed module root, ie. a block of top-level statements.
9964
export fn resolveModuleRoot(self: *mut Resolver, root: *ast::Node) -> Diagnostics throws (ResolveError) {
9965
    let case ast::NodeValue::Block(block) = root.value
9966
        else panic "resolveModuleRoot: expected block for module root";
9967
9968
    enterScope(self, root);
9969
    try resolveModuleDecls(self, &block) catch {
9970
        return Diagnostics { errors: self.errors };
9971
    };
9972
    try resolveModuleDefs(self, &block) catch {
9973
        return Diagnostics { errors: self.errors };
9974
    };
9975
    exitScope(self);
9976
    setNodeType(self, root, Type::Void);
9977
9978
    try closeGenericFnSpecializations(self) catch {
9979
        return Diagnostics { errors: self.errors };
9980
    };
9981
    try validateGenericDataRoots(self) catch {
9982
        return Diagnostics { errors: self.errors };
9983
    };
9984
    return Diagnostics { errors: self.errors };
9985
}
9986
9987
/// Analyze the module graph. This pass processes `mod` statements, creating symbols
9988
/// and scopes for them, and also binds type names in each module so that cross-module
9989
/// type references work regardless of declaration order.
9990
fn resolveModuleGraph(self: *mut Resolver, block: *ast::Block) throws (ResolveError) {
9991
    try bindTypeNames(self, block);
9992
9993
    for node in block.statements {
9994
        if let case ast::NodeValue::Mod(decl) = node.value {
9995
            try resolveModGraph(self, node, decl);
9996
        }
9997
    }
9998
}
9999
10000
/// Bind all type names in a module.
10001
/// Skips declarations that have already been bound.
10002
fn bindTypeNames(self: *mut Resolver, block: *ast::Block) throws (ResolveError) {
10003
    for node in block.statements {
10004
        match node.value {
10005
            case ast::NodeValue::RecordDecl(decl) => {
10006
                if symbolFor(self, node) == nil {
10007
                    try bindTypeName(self, node, decl.name, decl.attrs) catch {};
10008
                }
10009
            }
10010
            case ast::NodeValue::UnionDecl(decl) => {
10011
                if symbolFor(self, node) == nil {
10012
                    try bindTypeName(self, node, decl.name, decl.attrs) catch {};
10013
                }
10014
            }
10015
            case ast::NodeValue::TraitDecl { name, attrs, .. } => {
10016
                if symbolFor(self, node) == nil {
10017
                    try bindTraitName(self, node, name, attrs) catch {};
10018
                }
10019
            }
10020
            else => {}
10021
        }
10022
    }
10023
}
10024
10025
/// Resolve all type bodies in a module.
10026
fn resolveTypeBodies(self: *mut Resolver, block: *ast::Block) throws (ResolveError) {
10027
    for node in block.statements {
10028
        match node.value {
10029
            case ast::NodeValue::RecordDecl(decl) => {
10030
                if decl.params.len > 0 {
10031
                    try resolveGenericDataTemplate(
10032
                        self, node, decl.params, decl.fields, decl.derives, true,
10033
                    ) catch {};
10034
                } else {
10035
                    try resolveRecordBody(self, node, decl) catch {
10036
                        // Continue resolving other types even if one fails.
10037
                    };
10038
                }
10039
            }
10040
            case ast::NodeValue::UnionDecl(decl) => {
10041
                if decl.params.len > 0 {
10042
                    try resolveGenericDataTemplate(
10043
                        self, node, decl.params, decl.variants, decl.derives, false,
10044
                    ) catch {};
10045
                } else {
10046
                    try resolveUnionBody(self, node, decl) catch {
10047
                        // Continue resolving other types even if one fails.
10048
                    };
10049
                }
10050
            }
10051
            case ast::NodeValue::TraitDecl { supertraits, methods, .. } => {
10052
                try resolveTraitBody(self, node, supertraits, methods) catch {
10053
                    // Continue resolving other types even if one fails.
10054
                };
10055
            }
10056
            else => {
10057
                // Ignore other declarations.
10058
            }
10059
        }
10060
    }
10061
}
10062
10063
/// Analyze module declarations. This pass processes all top-level statements. When it hits
10064
/// a `mod` statement, it recurses inside the module, analyzing its statements. Module import
10065
/// statements (`use`) are processed here, and make use of the module graph established in the
10066
/// previous pass.
10067
///
10068
/// This function uses a two-phase approach:
10069
/// Phase 1: Bind all type names to allow forward references and mutual recursion.
10070
/// Phase 2: Resolve type bodies, ie. field types, variant types, etc.
10071
fn resolveModuleDecls(res: *mut Resolver, block: *ast::Block) throws (ResolveError) {
10072
    // Phase 1: Bind all type names as placeholders.
10073
    try bindTypeNames(res, block);
10074
    // Phase 2: Process imports so names available from the module graph can
10075
    // be used in function signatures.
10076
    for node in block.statements {
10077
        if let case ast::NodeValue::Use(decl) = node.value {
10078
            try resolveUse(res, node, decl);
10079
        }
10080
    }
10081
    // Phase 3: Bind function signatures so that function references are
10082
    // available in constant and static initializers.
10083
    for node in block.statements {
10084
        if let case ast::NodeValue::FnDecl(decl) = node.value {
10085
            try resolveFnDecl(res, node, decl);
10086
        }
10087
    }
10088
    // Phase 4: Process constants before submodules, so that child modules
10089
    // can reference parent constants via `super::`.
10090
    for node in block.statements {
10091
        if let case ast::NodeValue::ConstDecl(_) = node.value {
10092
            try infer(res, node);
10093
        }
10094
    }
10095
    // Phase 5: Process submodule declarations -- recurses into child modules.
10096
    // Child modules may trigger on-demand type resolution via
10097
    // [`ensureNominalResolved`] which switches to the declaring module's
10098
    // scope.
10099
    for node in block.statements {
10100
        if let case ast::NodeValue::Mod(decl) = node.value {
10101
            try resolveModDecl(res, node, decl);
10102
        }
10103
    }
10104
    // Phase 5b: Process wildcard imports after submodules are resolved,
10105
    // so that transitive re-exports (export use foo::*) are visible.
10106
    for node in block.statements {
10107
        if let case ast::NodeValue::Use(decl) = node.value {
10108
            if decl.wildcard {
10109
                try resolveUse(res, node, decl);
10110
            }
10111
        }
10112
    }
10113
    // Phase 6: Resolve type bodies (record fields, union variants).
10114
    try resolveTypeBodies(res, block);
10115
    // Phase 7: Process all other declarations (statics, etc.).
10116
    for stmt in block.statements {
10117
        try visitDecl(res, stmt);
10118
    }
10119
}
10120
10121
/// Maximum number of linear bindings active in one function.
10122
constant MAX_LINEAR_BINDINGS: u32 = 32;
10123
/// Maximum nesting depth tracked for loops.
10124
constant MAX_LINEAR_LOOP_DEPTH: u32 = 16;
10125
10126
/// How an expression uses a linear result.
10127
union LinearUse {
10128
    Consume,
10129
    Observe,
10130
    Borrow,
10131
    Discard,
10132
    Place,
10133
}
10134
10135
/// Per-control-flow-path ownership state.
10136
record LinearEnv {
10137
    symbols: [?*mut Symbol; MAX_LINEAR_BINDINGS],
10138
    available: u64,
10139
    len: u32,
10140
    terminated: bool,
10141
}
10142
10143
/// Function-local exact-use checker state.
10144
record LinearChecker {
10145
    resolver: *mut Resolver,
10146
    loopMarks: [u32; MAX_LINEAR_LOOP_DEPTH],
10147
    loopAvailable: [u64; MAX_LINEAR_LOOP_DEPTH],
10148
    loopExitAvailable: [u64; MAX_LINEAR_LOOP_DEPTH],
10149
    loopHasNaturalExit: [bool; MAX_LINEAR_LOOP_DEPTH],
10150
    loopBreakSeen: [bool; MAX_LINEAR_LOOP_DEPTH],
10151
    loopDepth: u32,
10152
}
10153
10154
/// Find a tracked binding by symbol identity.
10155
fn findLinearBinding(env: *LinearEnv, sym: *mut Symbol) -> ?u32 {
10156
    for i in 0..env.len {
10157
        if let bound = env.symbols[i]; bound == sym {
10158
            return i;
10159
        }
10160
    }
10161
    return nil;
10162
}
10163
10164
/// Return whether a tracked binding is still available.
10165
fn linearBindingAvailable(env: *LinearEnv, index: u32) -> bool {
10166
    return (env.available & ((1 as u64) << (index as u64))) <> 0;
10167
}
10168
10169
/// Add a local binding when its resolved type is linear.
10170
fn addLinearBinding(checker: *mut LinearChecker, env: *mut LinearEnv, node: *ast::Node)
10171
    throws (ResolveError)
10172
{
10173
    let sym = symbolFor(checker.resolver, node) else return;
10174
    let case SymbolData::Value { type: ty, .. } = sym.data else return;
10175
    if not isLinear(ty) {
10176
        return;
10177
    }
10178
    if env.len >= MAX_LINEAR_BINDINGS {
10179
        throw emitError(checker.resolver, node, ErrorKind::Internal);
10180
    }
10181
    set env.symbols[env.len] = sym;
10182
    set env.available |= (1 as u64) << (env.len as u64);
10183
    set env.len += 1;
10184
}
10185
10186
/// Require all bindings introduced after `start` to have been consumed.
10187
fn finishLinearScope(
10188
    checker: *mut LinearChecker,
10189
    env: *mut LinearEnv,
10190
    start: u32,
10191
) throws (ResolveError) {
10192
    if not env.terminated {
10193
        for i in start..env.len {
10194
            if linearBindingAvailable(env, i) {
10195
                let sym = env.symbols[i] else panic "finishLinearScope: missing symbol";
10196
                throw emitError(
10197
                    checker.resolver,
10198
                    sym.node,
10199
                    ErrorKind::LinearNotConsumed(sym.name),
10200
                );
10201
            }
10202
        }
10203
    }
10204
    set env.len = start;
10205
}
10206
10207
/// Consume a tracked identifier exactly once.
10208
fn consumeLinearIdent(
10209
    checker: *mut LinearChecker,
10210
    env: *mut LinearEnv,
10211
    node: *ast::Node,
10212
) throws (ResolveError) {
10213
    let sym = symbolFor(checker.resolver, node) else return;
10214
    let index = findLinearBinding(env, sym) else return;
10215
    if not linearBindingAvailable(env, index) {
10216
        throw emitError(
10217
            checker.resolver,
10218
            node,
10219
            ErrorKind::LinearUseAfterConsume(sym.name),
10220
        );
10221
    }
10222
    set env.available &= ~((1 as u64) << (index as u64));
10223
}
10224
10225
/// Verify that two live branches agree on every outer binding.
10226
fn joinLinearBranches(
10227
    checker: *mut LinearChecker,
10228
    env: *mut LinearEnv,
10229
    left: LinearEnv,
10230
    right: LinearEnv,
10231
    node: *ast::Node,
10232
) throws (ResolveError) {
10233
    if left.terminated and right.terminated {
10234
        set *env = left;
10235
        set env.terminated = true;
10236
        return;
10237
    }
10238
    if left.terminated {
10239
        set *env = right;
10240
        return;
10241
    }
10242
    if right.terminated {
10243
        set *env = left;
10244
        return;
10245
    }
10246
    assert left.len == right.len, "joinLinearBranches: scope mismatch";
10247
    for i in 0..left.len {
10248
        if linearBindingAvailable(&left, i) <> linearBindingAvailable(&right, i) {
10249
            let sym = left.symbols[i] else panic "joinLinearBranches: missing symbol";
10250
            throw emitError(
10251
                checker.resolver,
10252
                node,
10253
                ErrorKind::LinearBranchMismatch(sym.name),
10254
            );
10255
        }
10256
    }
10257
    set *env = left;
10258
}
10259
10260
/// Require all current bindings to be consumed at a function exit.
10261
fn finishLinearExit(
10262
    checker: *mut LinearChecker,
10263
    env: *mut LinearEnv,
10264
) throws (ResolveError) {
10265
    for i in 0..env.len {
10266
        if linearBindingAvailable(env, i) {
10267
            let sym = env.symbols[i] else panic "finishLinearExit: missing symbol";
10268
            throw emitError(
10269
                checker.resolver,
10270
                sym.node,
10271
                ErrorKind::LinearNotConsumed(sym.name),
10272
            );
10273
        }
10274
    }
10275
    set env.terminated = true;
10276
}
10277
10278
/// Find the local root borrowed or consumed by an argument expression.
10279
fn linearRootSymbol(self: *mut Resolver, node: *ast::Node) -> ?*mut Symbol {
10280
    match node.value {
10281
        case ast::NodeValue::Ident(_) => return symbolFor(self, node),
10282
        case ast::NodeValue::AddressOf(addr) => return linearRootSymbol(self, addr.target),
10283
        case ast::NodeValue::FieldAccess(access) =>
10284
            return linearRootSymbol(self, access.parent),
10285
        case ast::NodeValue::Subscript { container, .. } =>
10286
            return linearRootSymbol(self, container),
10287
        case ast::NodeValue::GenericApply(_) => return nil,
10288
        case ast::NodeValue::Deref(target) => return linearRootSymbol(self, target),
10289
        else => return nil,
10290
    }
10291
}
10292
10293
/// Add the value identifiers introduced by a pattern.
10294
fn addLinearPatternBindings(
10295
    checker: *mut LinearChecker,
10296
    env: *mut LinearEnv,
10297
    pattern: *ast::Node,
10298
) throws (ResolveError) {
10299
    match pattern.value {
10300
        case ast::NodeValue::Ident(_) => try addLinearBinding(checker, env, pattern),
10301
        case ast::NodeValue::Call(call) => {
10302
            for arg in call.args {
10303
                try addLinearPatternBindings(checker, env, arg);
10304
            }
10305
        }
10306
        case ast::NodeValue::RecordLit(lit) => {
10307
            for fieldNode in lit.fields {
10308
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
10309
                    else panic "addLinearPatternBindings: expected field";
10310
                try addLinearPatternBindings(checker, env, field.value);
10311
            }
10312
        }
10313
        case ast::NodeValue::ArrayLit(items) => {
10314
            for item in items {
10315
                try addLinearPatternBindings(checker, env, item);
10316
            }
10317
        }
10318
        else => {}
10319
    }
10320
}
10321
10322
/// Check a lexical block and exact-use of locals introduced in it.
10323
fn checkLinearBlock(
10324
    checker: *mut LinearChecker,
10325
    env: *mut LinearEnv,
10326
    node: *ast::Node,
10327
) throws (ResolveError) {
10328
    let start = env.len;
10329
    let case ast::NodeValue::Block(block) = node.value
10330
        else panic "checkLinearBlock: expected block";
10331
    for stmt in block.statements {
10332
        if env.terminated {
10333
            break;
10334
        }
10335
        try checkLinearNode(checker, env, stmt, LinearUse::Discard);
10336
    }
10337
    try finishLinearScope(checker, env, start);
10338
}
10339
10340
/// Push a repeated-control-flow boundary.
10341
fn enterLinearLoop(checker: *mut LinearChecker, env: *LinearEnv) {
10342
    assert checker.loopDepth < MAX_LINEAR_LOOP_DEPTH, "linear loop nesting overflow";
10343
    let depth = checker.loopDepth;
10344
    set checker.loopMarks[depth] = env.len;
10345
    set checker.loopAvailable[depth] = env.available;
10346
    set checker.loopExitAvailable[depth] = env.available;
10347
    set checker.loopHasNaturalExit[depth] = false;
10348
    set checker.loopBreakSeen[depth] = false;
10349
    set checker.loopDepth += 1;
10350
}
10351
10352
/// Require a repeated body's outer bindings to match its entry state.
10353
fn checkLinearLoopBackEdge(
10354
    checker: *mut LinearChecker,
10355
    env: *LinearEnv,
10356
    node: *ast::Node,
10357
) throws (ResolveError) {
10358
    if env.terminated {
10359
        return;
10360
    }
10361
    assert checker.loopDepth > 0, "linear loop back edge outside loop";
10362
    let depth = checker.loopDepth - 1;
10363
    let mark = checker.loopMarks[depth];
10364
    let entryAvailable = checker.loopAvailable[depth];
10365
    for i in 0..mark {
10366
        let bit = (1 as u64) << (i as u64);
10367
        if (env.available & bit) <> (entryAvailable & bit) {
10368
            let sym = env.symbols[i] else panic "checkLinearLoopBackEdge: missing symbol";
10369
            throw emitError(
10370
                checker.resolver,
10371
                node,
10372
                ErrorKind::LinearBranchMismatch(sym.name),
10373
            );
10374
        }
10375
    }
10376
}
10377
10378
/// Record the ownership state of a loop's condition-false exit.
10379
fn setLinearLoopNaturalExit(checker: *mut LinearChecker, env: *LinearEnv) {
10380
    assert checker.loopDepth > 0, "linear loop exit outside loop";
10381
    let depth = checker.loopDepth - 1;
10382
    set checker.loopExitAvailable[depth] = env.available;
10383
    set checker.loopHasNaturalExit[depth] = true;
10384
}
10385
10386
/// Require a break exit to agree with every other exit from this loop.
10387
fn checkLinearLoopBreak(
10388
    checker: *mut LinearChecker,
10389
    env: *LinearEnv,
10390
    node: *ast::Node,
10391
) throws (ResolveError) {
10392
    assert checker.loopDepth > 0, "linear loop break outside loop";
10393
    let depth = checker.loopDepth - 1;
10394
    let mark = checker.loopMarks[depth];
10395
    if checker.loopHasNaturalExit[depth] or checker.loopBreakSeen[depth] {
10396
        let expected = checker.loopExitAvailable[depth];
10397
        for i in 0..mark {
10398
            let bit = (1 as u64) << (i as u64);
10399
            if (env.available & bit) <> (expected & bit) {
10400
                let sym = env.symbols[i] else panic "checkLinearLoopBreak: missing symbol";
10401
                throw emitError(
10402
                    checker.resolver,
10403
                    node,
10404
                    ErrorKind::LinearBranchMismatch(sym.name),
10405
                );
10406
            }
10407
        }
10408
    } else {
10409
        set checker.loopExitAvailable[depth] = env.available;
10410
    }
10411
    set checker.loopBreakSeen[depth] = true;
10412
}
10413
10414
/// Pop a repeated-control-flow boundary.
10415
fn exitLinearLoop(checker: *mut LinearChecker) {
10416
    assert checker.loopDepth > 0, "exitLinearLoop: not in loop";
10417
    set checker.loopDepth -= 1;
10418
}
10419
10420
/// Check a conditional and merge its ownership states.
10421
fn checkLinearIf(
10422
    checker: *mut LinearChecker,
10423
    env: *mut LinearEnv,
10424
    node: *ast::Node,
10425
    conditional: ast::If,
10426
) throws (ResolveError) {
10427
    try checkLinearNode(checker, env, conditional.condition, LinearUse::Consume);
10428
    let base = *env;
10429
    let mut thenEnv = base;
10430
    try checkLinearNode(checker, &mut thenEnv, conditional.thenBranch, LinearUse::Discard);
10431
    let mut elseEnv = base;
10432
    if let branch = conditional.elseBranch {
10433
        try checkLinearNode(checker, &mut elseEnv, branch, LinearUse::Discard);
10434
    }
10435
    try joinLinearBranches(checker, env, thenEnv, elseEnv, node);
10436
}
10437
10438
/// Check an expression conditional and merge its ownership states.
10439
fn checkLinearCondExpr(
10440
    checker: *mut LinearChecker,
10441
    env: *mut LinearEnv,
10442
    node: *ast::Node,
10443
    conditional: ast::CondExpr,
10444
    usage: LinearUse,
10445
) throws (ResolveError) {
10446
    try checkLinearNode(checker, env, conditional.condition, LinearUse::Consume);
10447
    let base = *env;
10448
    let mut thenEnv = base;
10449
    try checkLinearNode(checker, &mut thenEnv, conditional.thenExpr, usage);
10450
    let mut elseEnv = base;
10451
    try checkLinearNode(checker, &mut elseEnv, conditional.elseExpr, usage);
10452
    try joinLinearBranches(checker, env, thenEnv, elseEnv, node);
10453
}
10454
10455
/// Check a match expression, including ownership transferred into patterns.
10456
fn checkLinearMatch(
10457
    checker: *mut LinearChecker,
10458
    env: *mut LinearEnv,
10459
    node: *ast::Node,
10460
    matchExpr: ast::Match,
10461
) throws (ResolveError) {
10462
    try checkLinearNode(checker, env, matchExpr.subject, LinearUse::Consume);
10463
    let base = *env;
10464
    let mut haveResult = false;
10465
    let mut result = base;
10466
    for prongNode in matchExpr.prongs {
10467
        let case ast::NodeValue::MatchProng(prong) = prongNode.value
10468
            else panic "checkLinearMatch: expected prong";
10469
        let mut branch = base;
10470
        let bindingsStart = branch.len;
10471
        match prong.arm {
10472
            case ast::ProngArm::Case(patterns) => {
10473
                for pattern in patterns {
10474
                    try addLinearPatternBindings(checker, &mut branch, pattern);
10475
                }
10476
            }
10477
            case ast::ProngArm::Binding(binding) => {
10478
                try addLinearPatternBindings(checker, &mut branch, binding);
10479
            }
10480
            case ast::ProngArm::Else => {}
10481
        }
10482
        if prong.guard <> nil and branch.len > bindingsStart {
10483
            throw emitError(checker.resolver, prongNode, ErrorKind::LinearDiscard);
10484
        }
10485
        if let guard = prong.guard {
10486
            try checkLinearNode(checker, &mut branch, guard, LinearUse::Consume);
10487
        }
10488
        try checkLinearNode(checker, &mut branch, prong.body, LinearUse::Discard);
10489
        try finishLinearScope(checker, &mut branch, bindingsStart);
10490
        if haveResult {
10491
            try joinLinearBranches(checker, &mut result, result, branch, node);
10492
        } else {
10493
            set result = branch;
10494
            set haveResult = true;
10495
        }
10496
    }
10497
    if haveResult {
10498
        set *env = result;
10499
    }
10500
}
10501
10502
/// Check call-scoped loans and argument ownership transfers.
10503
fn checkLinearCall(
10504
    checker: *mut LinearChecker,
10505
    env: *mut LinearEnv,
10506
    node: *ast::Node,
10507
    call: ast::Call,
10508
) throws (ResolveError) {
10509
    try checkLinearNode(checker, env, call.callee, LinearUse::Observe);
10510
    let calleeTy = typeFor(checker.resolver, call.callee) else {
10511
        throw emitError(checker.resolver, call.callee, ErrorKind::Internal);
10512
    };
10513
    let case Type::Fn(info) = calleeTy else {
10514
        for arg in call.args {
10515
            try checkLinearNode(checker, env, arg, LinearUse::Consume);
10516
        }
10517
        return;
10518
    };
10519
    let mut roots: [?*mut Symbol; MAX_FN_PARAMS + 1] = undefined;
10520
    let mut exclusive: [bool; MAX_FN_PARAMS + 1] = undefined;
10521
    let mut rootsLen: u32 = 0;
10522
10523
    // Method function types exclude their implicit receiver. Account for it
10524
    // explicitly so owning receivers are consumed and reference receivers
10525
    // participate in call-scoped loan conflict checks.
10526
    if let case ast::NodeValue::FieldAccess(access) = call.callee.value {
10527
        let mut receiverClass = types::PointerClass::Unsafe;
10528
        let mut receiverMutable = false;
10529
        let mut haveReceiver = false;
10530
        match checker.resolver.nodeData.entries[node.id].extra {
10531
            case NodeExtra::TraitMethodCall { traitInfo, methodIndex } => {
10532
                let method = &traitInfo.methods[methodIndex];
10533
                set receiverClass = method.receiverClass;
10534
                set receiverMutable = method.mutable;
10535
                set haveReceiver = true;
10536
            }
10537
            case NodeExtra::GenericBoundMethodCall {
10538
                traitInfo, methodIndex, explicitReceiver, ..
10539
            } => {
10540
                if not explicitReceiver {
10541
                    let method = &traitInfo.methods[methodIndex];
10542
                    set receiverClass = method.receiverClass;
10543
                    set receiverMutable = method.mutable;
10544
                    set haveReceiver = true;
10545
                }
10546
            }
10547
            case NodeExtra::MethodCall { method } => {
10548
                set receiverClass = method.receiverClass;
10549
                set receiverMutable = method.mutable;
10550
                set haveReceiver = true;
10551
            }
10552
            else => {}
10553
        }
10554
        if haveReceiver {
10555
            if receiverClass <> types::PointerClass::Unsafe {
10556
                let root = linearRootSymbol(checker.resolver, access.parent);
10557
                if let rootSym = root {
10558
                    set roots[rootsLen] = rootSym;
10559
                    set exclusive[rootsLen] =
10560
                        receiverClass == types::PointerClass::Owned or receiverMutable;
10561
                    set rootsLen += 1;
10562
                }
10563
            }
10564
            if receiverClass == types::PointerClass::Ref {
10565
                try checkLinearNode(checker, env, access.parent, LinearUse::Borrow);
10566
            } else if receiverClass == types::PointerClass::Owned {
10567
                try checkLinearNode(checker, env, access.parent, LinearUse::Consume);
10568
            }
10569
        }
10570
    }
10571
10572
    for arg, i in call.args {
10573
        let expected = *info.paramTypes[i];
10574
        let root = linearRootSymbol(checker.resolver, arg);
10575
        let mut argExclusive = isLinear(expected);
10576
        if let case Type::Pointer(PointerType { class: types::PointerClass::Ref, mutable, .. }) = expected {
10577
            set argExclusive = mutable;
10578
        } else if let case Type::Slice(SliceType {
10579
            class: types::PointerClass::Ref, mutable, ..
10580
        }) = expected {
10581
            set argExclusive = mutable;
10582
        } else if let case Type::TraitObject(TraitObjectType {
10583
            class: types::PointerClass::Ref, mutable, ..
10584
        }) = expected {
10585
            set argExclusive = mutable;
10586
        }
10587
        if not isUnsafePointerType(expected) {
10588
            if let rootSym = root {
10589
                for j in 0..rootsLen {
10590
                    if let previous = roots[j] {
10591
                        if previous == rootSym and (exclusive[j] or argExclusive) {
10592
                            throw emitError(
10593
                                checker.resolver,
10594
                                arg,
10595
                                ErrorKind::BorrowConflict(rootSym.name),
10596
                            );
10597
                        }
10598
                    }
10599
                }
10600
                set roots[rootsLen] = rootSym;
10601
                set exclusive[rootsLen] = argExclusive;
10602
                set rootsLen += 1;
10603
            }
10604
        }
10605
        if isRefType(expected) {
10606
            try checkLinearNode(checker, env, arg, LinearUse::Borrow);
10607
        } else {
10608
            try checkLinearNode(checker, env, arg, LinearUse::Consume);
10609
        }
10610
    }
10611
}
10612
10613
/// Check a pattern conditional. Linear scrutinees require an exhaustive match.
10614
fn checkLinearIfLet(
10615
    checker: *mut LinearChecker,
10616
    env: *mut LinearEnv,
10617
    node: *ast::Node,
10618
    conditional: ast::IfLet,
10619
) throws (ResolveError) {
10620
    if let subjectTy = typeFor(checker.resolver, conditional.pattern.scrutinee);
10621
        isLinear(subjectTy)
10622
    {
10623
        throw emitError(
10624
            checker.resolver,
10625
            conditional.pattern.scrutinee,
10626
            ErrorKind::LinearPartialMove,
10627
        );
10628
    }
10629
    try checkLinearNode(
10630
        checker,
10631
        env,
10632
        conditional.pattern.scrutinee,
10633
        LinearUse::Consume,
10634
    );
10635
    let base = *env;
10636
    let mut thenEnv = base;
10637
    let bindingsStart = thenEnv.len;
10638
    try addLinearPatternBindings(checker, &mut thenEnv, conditional.pattern.pattern);
10639
    if let guard = conditional.pattern.guard {
10640
        try checkLinearNode(checker, &mut thenEnv, guard, LinearUse::Consume);
10641
    }
10642
    try checkLinearNode(checker, &mut thenEnv, conditional.thenBranch, LinearUse::Discard);
10643
    try finishLinearScope(checker, &mut thenEnv, bindingsStart);
10644
    let mut elseEnv = base;
10645
    if let branch = conditional.elseBranch {
10646
        try checkLinearNode(checker, &mut elseEnv, branch, LinearUse::Discard);
10647
    }
10648
    try joinLinearBranches(checker, env, thenEnv, elseEnv, node);
10649
}
10650
10651
/// Check one expression or statement under an ownership-use context.
10652
fn checkLinearNode(
10653
    checker: *mut LinearChecker,
10654
    env: *mut LinearEnv,
10655
    node: *ast::Node,
10656
    usage: LinearUse,
10657
) throws (ResolveError) {
10658
    if env.terminated {
10659
        return;
10660
    }
10661
    match node.value {
10662
        case ast::NodeValue::Ident(_) => {
10663
            if usage == LinearUse::Consume {
10664
                try consumeLinearIdent(checker, env, node);
10665
            }
10666
        }
10667
        case ast::NodeValue::ExprStmt(expr) => {
10668
            if let exprTy = typeFor(checker.resolver, expr) {
10669
                if isLinear(exprTy) {
10670
                    throw emitError(checker.resolver, expr, ErrorKind::LinearDiscard);
10671
                }
10672
            }
10673
            try checkLinearNode(checker, env, expr, LinearUse::Consume);
10674
        }
10675
        case ast::NodeValue::Block(_) => try checkLinearBlock(checker, env, node),
10676
        case ast::NodeValue::Let(binding) => {
10677
            if let case ast::NodeValue::Undef = binding.value.value {
10678
                if let bindingTy = typeFor(checker.resolver, binding.ident);
10679
                    isLinear(bindingTy)
10680
                {
10681
                    throw emitError(
10682
                        checker.resolver,
10683
                        binding.value,
10684
                        ErrorKind::LinearUndefined,
10685
                    );
10686
                }
10687
            }
10688
            try checkLinearNode(checker, env, binding.value, LinearUse::Consume);
10689
            try addLinearBinding(checker, env, node);
10690
        }
10691
        case ast::NodeValue::Assign(assign) => {
10692
            let mut target: ?u32 = nil;
10693
            if let leftTy = typeFor(checker.resolver, assign.left) {
10694
                if isLinear(leftTy) {
10695
                    if let case ast::NodeValue::Ident(_) = assign.left.value {
10696
                        if let sym = symbolFor(checker.resolver, assign.left) {
10697
                            set target = findLinearBinding(env, sym);
10698
                        }
10699
                    }
10700
                    if target == nil {
10701
                        throw emitError(
10702
                            checker.resolver,
10703
                            assign.left,
10704
                            ErrorKind::LinearOverwrite,
10705
                        );
10706
                    }
10707
                }
10708
            }
10709
            try checkLinearNode(checker, env, assign.left, LinearUse::Place);
10710
            try checkLinearNode(checker, env, assign.right, LinearUse::Consume);
10711
            if let index = target {
10712
                if linearBindingAvailable(env, index) {
10713
                    throw emitError(
10714
                        checker.resolver,
10715
                        assign.left,
10716
                        ErrorKind::LinearOverwrite,
10717
                    );
10718
                }
10719
                set env.available |= (1 as u64) << (index as u64);
10720
            }
10721
        }
10722
        case ast::NodeValue::Call(call) => try checkLinearCall(checker, env, node, call),
10723
        case ast::NodeValue::AddressOf(addr) => {
10724
            try checkLinearNode(checker, env, addr.target, LinearUse::Borrow);
10725
        }
10726
        case ast::NodeValue::Deref(target) => {
10727
            if let resultTy = typeFor(checker.resolver, node) {
10728
                if isLinear(resultTy) and usage == LinearUse::Consume {
10729
                    throw emitError(checker.resolver, node, ErrorKind::LinearPartialMove);
10730
                }
10731
            }
10732
            try checkLinearNode(checker, env, target, LinearUse::Observe);
10733
        }
10734
        case ast::NodeValue::FieldAccess(access) => {
10735
            if let resultTy = typeFor(checker.resolver, node) {
10736
                if isLinear(resultTy) and usage == LinearUse::Consume {
10737
                    throw emitError(checker.resolver, node, ErrorKind::LinearPartialMove);
10738
                }
10739
            }
10740
            try checkLinearNode(checker, env, access.parent, LinearUse::Observe);
10741
        }
10742
        case ast::NodeValue::ScopeAccess(_) => {}
10743
        case ast::NodeValue::Subscript { container, index } => {
10744
            if let resultTy = typeFor(checker.resolver, node) {
10745
                if isLinear(resultTy) and usage == LinearUse::Consume {
10746
                    throw emitError(checker.resolver, node, ErrorKind::LinearPartialMove);
10747
                }
10748
            }
10749
            try checkLinearNode(checker, env, container, LinearUse::Observe);
10750
            try checkLinearNode(checker, env, index, LinearUse::Consume);
10751
        }
10752
        case ast::NodeValue::GenericApply(_) => {
10753
            let extra = checker.resolver.nodeData.entries[node.id].extra;
10754
            if let case NodeExtra::GenericFnCall(_) = extra {
10755
                return;
10756
            }
10757
            if let case NodeExtra::GenericFnDependency(_) = extra {
10758
                return;
10759
            }
10760
            throw emitError(checker.resolver, node, ErrorKind::Internal);
10761
        }
10762
        case ast::NodeValue::RecordLit(lit) => {
10763
            for fieldNode in lit.fields {
10764
                let case ast::NodeValue::RecordLitField(field) = fieldNode.value
10765
                    else panic "checkLinearNode: expected field";
10766
                try checkLinearNode(checker, env, field.value, LinearUse::Consume);
10767
            }
10768
        }
10769
        case ast::NodeValue::ArrayLit(items) => {
10770
            for item in items {
10771
                try checkLinearNode(checker, env, item, LinearUse::Consume);
10772
            }
10773
        }
10774
        case ast::NodeValue::ArrayRepeatLit(repeat) => {
10775
            if let itemTy = typeFor(checker.resolver, repeat.item) {
10776
                if isLinear(itemTy) {
10777
                    throw emitError(
10778
                        checker.resolver,
10779
                        repeat.item,
10780
                        ErrorKind::LinearDiscard,
10781
                    );
10782
                }
10783
            }
10784
            try checkLinearNode(checker, env, repeat.item, LinearUse::Consume);
10785
            try checkLinearNode(checker, env, repeat.count, LinearUse::Consume);
10786
        }
10787
        case ast::NodeValue::BinOp(op) => {
10788
            try checkLinearNode(checker, env, op.left, LinearUse::Consume);
10789
            try checkLinearNode(checker, env, op.right, LinearUse::Consume);
10790
        }
10791
        case ast::NodeValue::UnOp(op) => {
10792
            try checkLinearNode(checker, env, op.value, LinearUse::Consume);
10793
        }
10794
        case ast::NodeValue::As(expr) => {
10795
            try checkLinearNode(checker, env, expr.value, LinearUse::Consume);
10796
        }
10797
        case ast::NodeValue::Range(range) => {
10798
            if let start = range.start {
10799
                try checkLinearNode(checker, env, start, LinearUse::Consume);
10800
            }
10801
            if let end = range.end {
10802
                try checkLinearNode(checker, env, end, LinearUse::Consume);
10803
            }
10804
        }
10805
        case ast::NodeValue::BuiltinCall { args, .. } => {
10806
            for arg in args {
10807
                try checkLinearNode(checker, env, arg, LinearUse::Consume);
10808
            }
10809
        }
10810
        case ast::NodeValue::If(conditional) => {
10811
            try checkLinearIf(checker, env, node, conditional);
10812
        }
10813
        case ast::NodeValue::CondExpr(conditional) => {
10814
            try checkLinearCondExpr(checker, env, node, conditional, usage);
10815
        }
10816
        case ast::NodeValue::IfLet(conditional) => {
10817
            try checkLinearIfLet(checker, env, node, conditional);
10818
        }
10819
        case ast::NodeValue::LetElse(binding) => {
10820
            if let subjectTy = typeFor(checker.resolver, binding.pattern.scrutinee);
10821
                isLinear(subjectTy)
10822
            {
10823
                throw emitError(
10824
                    checker.resolver,
10825
                    binding.pattern.scrutinee,
10826
                    ErrorKind::LinearPartialMove,
10827
                );
10828
            }
10829
            try checkLinearNode(
10830
                checker,
10831
                env,
10832
                binding.pattern.scrutinee,
10833
                LinearUse::Consume,
10834
            );
10835
            let base = *env;
10836
            let mut guardedEnv = base;
10837
            if let guard = binding.pattern.guard {
10838
                try checkLinearNode(checker, &mut guardedEnv, guard, LinearUse::Consume);
10839
            }
10840
            let mut successEnv = guardedEnv;
10841
            try addLinearPatternBindings(
10842
                checker,
10843
                &mut successEnv,
10844
                binding.pattern.pattern,
10845
            );
10846
            let mut fallbackEnv = base;
10847
            try checkLinearNode(
10848
                checker,
10849
                &mut fallbackEnv,
10850
                binding.elseBranch,
10851
                LinearUse::Consume,
10852
            );
10853
            if binding.pattern.guard <> nil {
10854
                let mut guardFallbackEnv = guardedEnv;
10855
                try checkLinearNode(
10856
                    checker,
10857
                    &mut guardFallbackEnv,
10858
                    binding.elseBranch,
10859
                    LinearUse::Consume,
10860
                );
10861
                try joinLinearBranches(
10862
                    checker,
10863
                    &mut fallbackEnv,
10864
                    fallbackEnv,
10865
                    guardFallbackEnv,
10866
                    binding.elseBranch,
10867
                );
10868
            }
10869
            if let case ast::PatternKind::Binding = binding.pattern.kind {
10870
                try addLinearPatternBindings(
10871
                    checker,
10872
                    &mut fallbackEnv,
10873
                    binding.pattern.pattern,
10874
                );
10875
            }
10876
            try joinLinearBranches(checker, env, successEnv, fallbackEnv, node);
10877
        }
10878
        case ast::NodeValue::Match(matchExpr) => {
10879
            try checkLinearMatch(checker, env, node, matchExpr);
10880
        }
10881
        case ast::NodeValue::Try(tryExpr) => {
10882
            try checkLinearNode(checker, env, tryExpr.expr, usage);
10883
            let success = *env;
10884
            for catchNode in tryExpr.catches {
10885
                let case ast::NodeValue::CatchClause(catchClause) = catchNode.value
10886
                    else panic "checkLinearNode: expected catch";
10887
                let mut branch = success;
10888
                let start = branch.len;
10889
                if let binding = catchClause.binding {
10890
                    try addLinearBinding(checker, &mut branch, binding);
10891
                }
10892
                try checkLinearNode(checker, &mut branch, catchClause.body, usage);
10893
                try finishLinearScope(checker, &mut branch, start);
10894
                try joinLinearBranches(checker, env, *env, branch, node);
10895
            }
10896
        }
10897
        case ast::NodeValue::While(whileStmt) => {
10898
            enterLinearLoop(checker, env);
10899
            try checkLinearNode(checker, env, whileStmt.condition, LinearUse::Consume);
10900
            let conditionExit = *env;
10901
            setLinearLoopNaturalExit(checker, &conditionExit);
10902
            let mut bodyEnv = conditionExit;
10903
            try checkLinearNode(checker, &mut bodyEnv, whileStmt.body, LinearUse::Discard);
10904
            try checkLinearLoopBackEdge(checker, &bodyEnv, whileStmt.body);
10905
            exitLinearLoop(checker);
10906
            set *env = conditionExit;
10907
            if let elseBranch = whileStmt.elseBranch {
10908
                let mut elseEnv = conditionExit;
10909
                try checkLinearNode(
10910
                    checker,
10911
                    &mut elseEnv,
10912
                    elseBranch,
10913
                    LinearUse::Discard,
10914
                );
10915
                try joinLinearBranches(checker, env, conditionExit, elseEnv, node);
10916
            }
10917
        }
10918
        case ast::NodeValue::WhileLet(whileStmt) => {
10919
            if let subjectTy = typeFor(checker.resolver, whileStmt.pattern.scrutinee);
10920
                isLinear(subjectTy)
10921
            {
10922
                throw emitError(
10923
                    checker.resolver,
10924
                    whileStmt.pattern.scrutinee,
10925
                    ErrorKind::LinearPartialMove,
10926
                );
10927
            }
10928
            let base = *env;
10929
            enterLinearLoop(checker, env);
10930
            let mut bodyEnv = base;
10931
            try checkLinearNode(
10932
                checker,
10933
                &mut bodyEnv,
10934
                whileStmt.pattern.scrutinee,
10935
                LinearUse::Consume,
10936
            );
10937
            let mut conditionExit = bodyEnv;
10938
            let start = bodyEnv.len;
10939
            try addLinearPatternBindings(checker, &mut bodyEnv, whileStmt.pattern.pattern);
10940
            if let guard = whileStmt.pattern.guard {
10941
                try checkLinearNode(checker, &mut bodyEnv, guard, LinearUse::Consume);
10942
                let mut guardExit = bodyEnv;
10943
                try finishLinearScope(checker, &mut guardExit, start);
10944
                try joinLinearBranches(
10945
                    checker,
10946
                    &mut conditionExit,
10947
                    conditionExit,
10948
                    guardExit,
10949
                    guard,
10950
                );
10951
            }
10952
            setLinearLoopNaturalExit(checker, &conditionExit);
10953
            try checkLinearNode(checker, &mut bodyEnv, whileStmt.body, LinearUse::Discard);
10954
            try finishLinearScope(checker, &mut bodyEnv, start);
10955
            try checkLinearLoopBackEdge(checker, &bodyEnv, whileStmt.body);
10956
            exitLinearLoop(checker);
10957
            set *env = conditionExit;
10958
            if let elseBranch = whileStmt.elseBranch {
10959
                let mut elseEnv = conditionExit;
10960
                try checkLinearNode(
10961
                    checker,
10962
                    &mut elseEnv,
10963
                    elseBranch,
10964
                    LinearUse::Discard,
10965
                );
10966
                try joinLinearBranches(checker, env, conditionExit, elseEnv, node);
10967
            }
10968
        }
10969
        case ast::NodeValue::For(forStmt) => {
10970
            if let iterableTy = typeFor(checker.resolver, forStmt.iterable) {
10971
                if isLinear(iterableTy) {
10972
                    throw emitError(
10973
                        checker.resolver,
10974
                        forStmt.iterable,
10975
                        ErrorKind::LinearPartialMove,
10976
                    );
10977
                }
10978
            }
10979
            try checkLinearNode(checker, env, forStmt.iterable, LinearUse::Consume);
10980
            let base = *env;
10981
            enterLinearLoop(checker, env);
10982
            setLinearLoopNaturalExit(checker, &base);
10983
            let mut bodyEnv = base;
10984
            let start = bodyEnv.len;
10985
            try addLinearBinding(checker, &mut bodyEnv, forStmt.binding);
10986
            if let index = forStmt.index {
10987
                try addLinearBinding(checker, &mut bodyEnv, index);
10988
            }
10989
            try checkLinearNode(checker, &mut bodyEnv, forStmt.body, LinearUse::Discard);
10990
            try finishLinearScope(checker, &mut bodyEnv, start);
10991
            try checkLinearLoopBackEdge(checker, &bodyEnv, forStmt.body);
10992
            exitLinearLoop(checker);
10993
            set *env = base;
10994
            if let elseBranch = forStmt.elseBranch {
10995
                let mut elseEnv = base;
10996
                try checkLinearNode(
10997
                    checker,
10998
                    &mut elseEnv,
10999
                    elseBranch,
11000
                    LinearUse::Discard,
11001
                );
11002
                try joinLinearBranches(checker, env, base, elseEnv, node);
11003
            }
11004
        }
11005
        case ast::NodeValue::Loop { body } => {
11006
            let base = *env;
11007
            enterLinearLoop(checker, env);
11008
            let mut bodyEnv = base;
11009
            try checkLinearNode(checker, &mut bodyEnv, body, LinearUse::Discard);
11010
            try checkLinearLoopBackEdge(checker, &bodyEnv, body);
11011
            let depth = checker.loopDepth - 1;
11012
            let breakSeen = checker.loopBreakSeen[depth];
11013
            let exitAvailable = checker.loopExitAvailable[depth];
11014
            exitLinearLoop(checker);
11015
            set *env = base;
11016
            if breakSeen {
11017
                set env.available = exitAvailable;
11018
            } else {
11019
                set env.terminated = true;
11020
            }
11021
        }
11022
        case ast::NodeValue::Break => {
11023
            assert checker.loopDepth > 0, "linear loop control outside loop";
11024
            let start = checker.loopMarks[checker.loopDepth - 1];
11025
            try finishLinearScope(checker, env, start);
11026
            try checkLinearLoopBreak(checker, env, node);
11027
            set env.terminated = true;
11028
        }
11029
        case ast::NodeValue::Continue => {
11030
            assert checker.loopDepth > 0, "linear loop control outside loop";
11031
            let start = checker.loopMarks[checker.loopDepth - 1];
11032
            try finishLinearScope(checker, env, start);
11033
            try checkLinearLoopBackEdge(checker, env, node);
11034
            set env.terminated = true;
11035
        }
11036
        case ast::NodeValue::Return { value } => {
11037
            if let expr = value {
11038
                try checkLinearNode(checker, env, expr, LinearUse::Consume);
11039
            }
11040
            try finishLinearExit(checker, env);
11041
        }
11042
        case ast::NodeValue::Throw { expr } => {
11043
            try checkLinearNode(checker, env, expr, LinearUse::Consume);
11044
            try finishLinearExit(checker, env);
11045
        }
11046
        case ast::NodeValue::Panic { message } => {
11047
            if let expr = message {
11048
                try checkLinearNode(checker, env, expr, LinearUse::Consume);
11049
            }
11050
            set env.terminated = true;
11051
        }
11052
        case ast::NodeValue::Assert { condition, message } => {
11053
            try checkLinearNode(checker, env, condition, LinearUse::Consume);
11054
            if let expr = message {
11055
                try checkLinearNode(checker, env, expr, LinearUse::Consume);
11056
            }
11057
        }
11058
        else => {}
11059
    }
11060
}
11061
11062
/// Check exact-use ownership for one resolved function.
11063
fn checkLinearFn(
11064
    self: *mut Resolver,
11065
    receiver: ?*ast::Node,
11066
    params: *mut [*ast::Node],
11067
    body: *ast::Node,
11068
) throws (ResolveError) {
11069
    let mut checker = LinearChecker {
11070
        resolver: self,
11071
        loopMarks: [0; MAX_LINEAR_LOOP_DEPTH],
11072
        loopAvailable: [0; MAX_LINEAR_LOOP_DEPTH],
11073
        loopExitAvailable: [0; MAX_LINEAR_LOOP_DEPTH],
11074
        loopHasNaturalExit: [false; MAX_LINEAR_LOOP_DEPTH],
11075
        loopBreakSeen: [false; MAX_LINEAR_LOOP_DEPTH],
11076
        loopDepth: 0,
11077
    };
11078
    let mut env = LinearEnv {
11079
        symbols: [nil; MAX_LINEAR_BINDINGS],
11080
        available: 0,
11081
        len: 0,
11082
        terminated: false,
11083
    };
11084
    if let receiverNode = receiver {
11085
        try addLinearBinding(&mut checker, &mut env, receiverNode);
11086
    }
11087
    for paramNode in params {
11088
        let case ast::NodeValue::FnParam(_) = paramNode.value
11089
            else panic "checkLinearFn: expected parameter";
11090
        try addLinearBinding(&mut checker, &mut env, paramNode);
11091
    }
11092
    try checkLinearNode(&mut checker, &mut env, body, LinearUse::Discard);
11093
    try finishLinearScope(&mut checker, &mut env, 0);
11094
}
11095
11096
/// Analyze module definitions. This pass analyzes function bodies, recursing into sub-modules.
11097
fn resolveModuleDefs(self: *mut Resolver, block: *ast::Block) throws (ResolveError) {
11098
    for stmt in block.statements {
11099
        try visitDef(self, stmt);
11100
    }
11101
}
11102
11103
/// Resolve all packages.
11104
export fn resolve(self: *mut Resolver, graph: *module::ModuleGraph, packages: *[Pkg]) -> Diagnostics throws (ResolveError) {
11105
    set self.moduleGraph = graph;
11106
11107
    // 1. Bind all package roots to enable cross-package references.
11108
    for i in 0..packages.len {
11109
        let pkg = &packages[i];
11110
        // Enter a new scope for the module.
11111
        let enter = enterModuleScope(self, pkg.rootAst, pkg.rootEntry);
11112
        // Bind the package root module name in the global package scope.
11113
        try bindModuleIdent(self, pkg.rootEntry, enter.newScope, pkg.rootAst, 0, self.pkgScope);
11114
11115
        exitModuleScope(self, enter);
11116
    }
11117
    // 2. Resolve each package's contents.
11118
    for i in 0..packages.len {
11119
        let pkg = &packages[i];
11120
        let diags = try resolvePackage(self, pkg.rootEntry, pkg.rootAst);
11121
        if not success(&diags) {
11122
            return diags;
11123
        }
11124
        try closeGenericFnSpecializations(self) catch {
11125
            return Diagnostics { errors: self.errors };
11126
        };
11127
    }
11128
    // Data roots are validated after every package has had a chance to provide
11129
    // an explicit root for a shared specialization.
11130
    try validateGenericDataRoots(self) catch {
11131
        return Diagnostics { errors: self.errors };
11132
    };
11133
    return Diagnostics { errors: self.errors };
11134
}
11135
11136
/// Resolve a package.
11137
fn resolvePackage(self: *mut Resolver, rootEntry: *module::ModuleEntry, node: *ast::Node) -> Diagnostics throws (ResolveError) {
11138
    let rootId = rootEntry.id;
11139
    let scope = self.moduleScopes[rootId as u32]
11140
        else panic "resolvePackage: module scope not found";
11141
11142
    // Set up the module scope for this package.
11143
    set self.scope = scope;
11144
    set self.currentMod = rootId;
11145
    set self.genericRoots = 0;
11146
    set self.genericSpecializationCount = 0;
11147
11148
    let case ast::NodeValue::Block(block) = node.value
11149
        else panic "resolvePackage: expected block for module root";
11150
11151
    // Module graph analysis phase: bind all module name symbols and scopes.
11152
    try resolveModuleGraph(self, &block) catch {
11153
        assert self.errors.len > 0, "resolvePackage: failure should have diagnostics";
11154
        return Diagnostics { errors: self.errors };
11155
    };
11156
11157
    // Declaration phase: bind all names and analyze top-level declarations.
11158
    try resolveModuleDecls(self, &block) catch {
11159
        assert self.errors.len > 0, "resolvePackage: failure should have diagnostics";
11160
    };
11161
    if self.errors.len > 0 {
11162
        return Diagnostics { errors: self.errors };
11163
    }
11164
11165
    // Definition phase: analyze function bodies and sub-module definitions.
11166
    try resolveModuleDefs(self, &block) catch {
11167
        assert self.errors.len > 0, "resolvePackage: failure should have diagnostics";
11168
    };
11169
    setNodeType(self, node, Type::Void);
11170
11171
    return Diagnostics { errors: self.errors };
11172
}