lib/std/lang/resolver/printer.rad 25.5 KiB raw
1
//! Resolver scope printer.
2
use std::io;
3
use std::lang::ast;
4
use std::lang::types;
5
use std::lang::scanner;
6
use std::lang::module;
7
8
/// Print a span in `@offset:length` form.
9
fn printSpan(span: ast::Span) {
10
    io::print("@");
11
    io::printU32(span.offset);
12
    io::print(":");
13
    io::printU32(span.length);
14
}
15
16
/// Print a count mismatch message: `<prefix>: <verb> <expected>, got <actual>`.
17
fn printMismatch(prefix: *[u8], verb: *[u8], m: super::CountMismatch) {
18
    io::print(prefix);
19
    io::print(": ");
20
    io::print(verb);
21
    io::print(" ");
22
    io::printU32(m.expected);
23
    io::print(", got ");
24
    io::printU32(m.actual);
25
}
26
27
/// Print `<prefix>'<name>'`.
28
fn printQuoted(prefix: *[u8], name: *[u8]) {
29
    io::print(prefix);
30
    io::print(name);
31
    io::print("'");
32
}
33
34
/// Print a pointer-like type prefix.
35
unsafe fn printPtrPrefix(class: types::PointerClass, mutable: bool) {
36
    match class {
37
        case types::PointerClass::Owned => io::print("*"),
38
        case types::PointerClass::Ref => io::print("&"),
39
        case types::PointerClass::Region(region) => {
40
            io::print("&");
41
            io::print(region.name);
42
            io::print(" ");
43
        }
44
        case types::PointerClass::Unsafe => io::print("*unsafe "),
45
    }
46
    if mutable {
47
        io::print("mut ");
48
    }
49
}
50
51
/// Print a resolved type in a textual form.
52
unsafe fn printType(ty: super::Type) {
53
    printTypeBody(ty, false);
54
}
55
56
/// Print just the type name without detailed structure info.
57
unsafe fn printTypeName(ty: super::Type) {
58
    printTypeBody(ty, true);
59
}
60
61
/// Print a resolved type, optionally abbreviated for function signatures.
62
unsafe fn printTypeBody(ty: super::Type, brief: bool) {
63
    match ty {
64
        case super::Type::Unknown => {
65
            io::print("<unknown>");
66
        }
67
        case super::Type::Undefined => {
68
            io::print("<undefined>");
69
        }
70
        case super::Type::Int => {
71
            io::print("<int>");
72
        }
73
        case super::Type::Nil => {
74
            io::print("<nil>");
75
        }
76
        case super::Type::Opaque => {
77
            io::print("opaque");
78
        }
79
        case super::Type::Never => {
80
            io::print("!");
81
        }
82
        case super::Type::Void => {
83
            io::print("void");
84
        }
85
        case super::Type::Bool => {
86
            io::print("bool");
87
        }
88
        case super::Type::U8 => {
89
            io::print("u8");
90
        }
91
        case super::Type::U16 => {
92
            io::print("u16");
93
        }
94
        case super::Type::U32 => {
95
            io::print("u32");
96
        }
97
        case super::Type::U64 => {
98
            io::print("u64");
99
        }
100
        case super::Type::I8 => {
101
            io::print("i8");
102
        }
103
        case super::Type::I16 => {
104
            io::print("i16");
105
        }
106
        case super::Type::I32 => {
107
            io::print("i32");
108
        }
109
        case super::Type::I64 => {
110
            io::print("i64");
111
        }
112
        case super::Type::Cell { class, permission, payload } => {
113
            printPtrPrefix(class, false);
114
            io::print("cell ");
115
            if let region = permission {
116
                io::print(region.name);
117
                io::print(" ");
118
            }
119
            printTypeBody(*payload, brief);
120
        }
121
        case super::Type::Session(region) => {
122
            io::print("Session ");
123
            io::print(region.name);
124
        }
125
        case super::Type::Pointer { class, target, mutable } => {
126
            printPtrPrefix(class, mutable);
127
            printTypeBody(*target, brief);
128
        }
129
        case super::Type::Slice { class, item, mutable } => {
130
            printPtrPrefix(class, mutable);
131
            io::print("[");
132
            printTypeBody(*item, brief);
133
            io::print("]");
134
        }
135
        case super::Type::Array(array) => {
136
            io::print("[");
137
            printTypeBody(*array.item, brief);
138
            io::print("; ");
139
            io::printU32(array.length);
140
            io::print("]");
141
        }
142
        case super::Type::Optional(inner) => {
143
            io::print("?");
144
            printTypeBody(*inner, brief);
145
        }
146
        case super::Type::Fn(fnType) => {
147
            if fnType.isUnsafe {
148
                io::print("unsafe ");
149
            }
150
            io::print("fn(");
151
            for paramType, i in fnType.paramTypes {
152
                if i > 0 {
153
                    io::print(", ");
154
                }
155
                printTypeName(*paramType);
156
            }
157
            io::print(")");
158
            io::print(" -> ");
159
            printTypeName(*fnType.returnType);
160
            if fnType.throwList.len > 0 {
161
                io::print(" throws ");
162
                for throwType, i in fnType.throwList {
163
                    if i > 0 {
164
                        io::print(", ");
165
                    }
166
                    printTypeName(*throwType);
167
                }
168
            }
169
        }
170
        case super::Type::Nominal(info) => {
171
            if brief {
172
                printNominalTypeName(info);
173
            } else {
174
                printNominalType(info);
175
            }
176
        }
177
        case super::Type::TraitObject { class, traitInfo, mutable } => {
178
            printPtrPrefix(class, mutable);
179
            io::print("opaque ");
180
            io::print(traitInfo.name);
181
        }
182
        case super::Type::Range { start, end } => {
183
            if let s = start {
184
                printTypeBody(*s, brief);
185
            }
186
            io::print("..");
187
            if let e = end {
188
                printTypeBody(*e, brief);
189
            }
190
        }
191
    }
192
}
193
194
/// Print detailed information about a nominal type (record or union).
195
unsafe fn printNominalType(info: *unsafe super::NominalType) {
196
    match *info {
197
        case super::NominalType::Placeholder(_), super::NominalType::Resolving(_) => {
198
            io::print("<placeholder>");
199
        }
200
        case super::NominalType::Application(applied) => {
201
            printNominalTypeName(applied.base);
202
            printNominalArguments(applied);
203
        }
204
        case super::NominalType::Record(recordType) => {
205
            io::print("record {");
206
            if recordType.fields.len > 0 {
207
                io::print(" ");
208
                for i in 0..recordType.fields.len {
209
                    if i > 0 {
210
                        io::print(", ");
211
                    }
212
                    let field = &recordType.fields[i];
213
                    if let name = field.name {
214
                        io::print(name);
215
                        io::print(": ");
216
                    }
217
                    printTypeName(field.fieldType);
218
219
                    if i >= 4 and i < recordType.fields.len - 1 {
220
                        io::print(", ...");
221
                        break;
222
                    }
223
                }
224
                io::print(" ");
225
            }
226
            io::print("}");
227
        }
228
        case super::NominalType::Union(unionType) => {
229
            io::print("union {");
230
            if unionType.variants.len > 0 {
231
                io::print(" ");
232
                for i in 0..unionType.variants.len {
233
                    if i > 0 {
234
                        io::print(", ");
235
                    }
236
                    let variant = &unionType.variants[i];
237
                    io::print(variant.name);
238
                    io::print(": ");
239
                    printTypeName(variant.valueType);
240
241
                    if i >= 4 and i < unionType.variants.len - 1 {
242
                        io::print(", ...");
243
                        break;
244
                    }
245
                }
246
                io::print(" ");
247
            }
248
            io::print("}");
249
        }
250
    }
251
    if let applied = super::nominalApplication(info) {
252
        if let case super::NominalType::Application(_) = *info {
253
            return;
254
        }
255
        printNominalArguments(applied);
256
    }
257
}
258
259
/// Print just the type kind for a nominal type, without detailed info.
260
unsafe fn printNominalTypeName(info: *unsafe super::NominalType) {
261
    match *info {
262
        case super::NominalType::Placeholder(_), super::NominalType::Resolving(_) => {
263
            io::print("<placeholder>");
264
        }
265
        case super::NominalType::Application(applied) => {
266
            printNominalTypeName(applied.base);
267
            printNominalArguments(applied);
268
        }
269
        case super::NominalType::Record(_) => {
270
            io::print("<record>");
271
        }
272
        case super::NominalType::Union(_) => {
273
            io::print("<union>");
274
        }
275
    }
276
    if let applied = super::nominalApplication(info) {
277
        if let case super::NominalType::Application(_) = *info {
278
            return;
279
        }
280
        printNominalArguments(applied);
281
    }
282
}
283
284
/// Print a single diagnostic entry.
285
unsafe fn printError 'arena 'permission (err: &super::Error, res: &super::Resolver 'arena, graph: &module::ModuleGraph 'permission) {
286
    if let node = err.node {
287
        // Find the module containing this error.
288
        if let moduleEntry = super::moduleFor(res, err.moduleId) {
289
            // Get the source text if available.
290
            if let source = module::sourceFor(graph, moduleEntry) {
291
                // Convert offset to location.
292
                if let loc = scanner::getLocation(scanner::SourceLoc::File(moduleEntry.filePath), source, node.span.offset) {
293
                    // Print: filename:line:col: error: message
294
                    if let case scanner::SourceLoc::File(path) = loc.source {
295
                        io::print(path);
296
                        io::print(":");
297
                    }
298
                    io::printU32(loc.line as u32);
299
                    io::print(":");
300
                    io::printU32(loc.col as u32);
301
                    io::print(": error: ");
302
                } else {
303
                    io::print("error ");
304
                    io::print(" ");
305
                    printSpan(node.span);
306
                    io::print(": ");
307
                }
308
            } else {
309
                io::print(moduleEntry.name);
310
                io::print(": ");
311
                io::print("error ");
312
                io::print(" ");
313
                printSpan(node.span);
314
                io::print(": ");
315
            }
316
        }
317
    } else {
318
        io::print("error: ");
319
    }
320
    // Print the error message.
321
    match err.kind {
322
        case super::ErrorKind::TypeMismatch(mismatch) => {
323
            io::print("type mismatch: expected ");
324
            printType(mismatch.expected);
325
            io::print(", got ");
326
            printType(mismatch.actual);
327
        }
328
        case super::ErrorKind::UnresolvedSymbol(name) => {
329
            printQuoted("unresolved symbol '", name);
330
        }
331
        case super::ErrorKind::DuplicateBinding(name) => {
332
            printQuoted("duplicate binding '", name);
333
        }
334
        case super::ErrorKind::FnArgCountMismatch(m) =>
335
            printMismatch("function argument count mismatch", "expected", m),
336
        case super::ErrorKind::FnThrowCountMismatch(m) =>
337
            printMismatch("function throws count mismatch", "expected", m),
338
        case super::ErrorKind::RecordFieldCountMismatch(m) =>
339
            printMismatch("record field count mismatch", "expected", m),
340
        case super::ErrorKind::RecordFieldMissing(name) => {
341
            printQuoted("record field missing: '", name);
342
        }
343
        case super::ErrorKind::RecordFieldUnknown(name) => {
344
            printQuoted("record field unknown: '", name);
345
        }
346
        case super::ErrorKind::InvalidAsCast(info) => {
347
            io::print("invalid cast: cannot cast ");
348
            printType(info.from);
349
            io::print(" to ");
350
            printType(info.to);
351
        }
352
        case super::ErrorKind::ExpectedIterable => {
353
            io::print("expected iterable type");
354
        }
355
        case super::ErrorKind::FnMissingReturn => {
356
            io::print("function must return a value on all paths");
357
        }
358
        case super::ErrorKind::UnionMatchNonExhaustive(name) => {
359
            printQuoted("union match non-exhaustive: missing case for variant '", name);
360
        }
361
        case super::ErrorKind::OptionalMatchMissingValue => {
362
            io::print("optional match non-exhaustive: missing value case");
363
        }
364
        case super::ErrorKind::OptionalMatchMissingNil => {
365
            io::print("optional match non-exhaustive: missing nil case");
366
        }
367
        case super::ErrorKind::BoolMatchMissing(val) => {
368
            io::print("bool match non-exhaustive: missing case for `");
369
            io::print("true" if val else "false");
370
            io::print("`");
371
        }
372
        case super::ErrorKind::MatchNonExhaustive => {
373
            io::print("match non-exhaustive: requires `else` or binding catch-all");
374
        }
375
        case super::ErrorKind::DuplicateCatchAll => {
376
            io::print("match has multiple catch-all prongs");
377
        }
378
        case super::ErrorKind::CatchAllMustBeLast => {
379
            io::print("match catch-all prong must be last");
380
        }
381
        case super::ErrorKind::DuplicateMatchPattern => {
382
            io::print("match has duplicate pattern");
383
        }
384
        case super::ErrorKind::UnreachableElse => {
385
            io::print("match has unreachable `else`, all cases are already handled");
386
        }
387
        case super::ErrorKind::ImmutableBinding => {
388
            io::print("cannot assign to immutable binding");
389
        }
390
        case super::ErrorKind::ConstExprRequired => {
391
            io::print("expected compile-time constant expression");
392
        }
393
        case super::ErrorKind::SymbolOverflow => {
394
            io::print("symbol arena overflow");
395
        }
396
        case super::ErrorKind::NumericLiteralOverflow => {
397
            io::print("numeric literal overflow");
398
        }
399
        case super::ErrorKind::RecordFieldStyleMismatch => {
400
            io::print("brace syntax not allowed for tuple-style records");
401
        }
402
        case super::ErrorKind::ExpectedIdentifier => {
403
            io::print("expected identifier");
404
        }
405
        case super::ErrorKind::ExpectedOptional => {
406
            io::print("expected optional type");
407
        }
408
        case super::ErrorKind::ExpectedNumeric => {
409
            io::print("expected numeric type");
410
        }
411
        case super::ErrorKind::ExpectedPointer => {
412
            io::print("expected pointer type");
413
        }
414
        case super::ErrorKind::InvalidSliceAllocator => {
415
            io::print("expected allocator with func callback and matching opaque ctx pointer");
416
        }
417
        case super::ErrorKind::ExpectedRecord => {
418
            io::print("expected record type");
419
        }
420
        case super::ErrorKind::ExpectedIndexable => {
421
            io::print("expected array or slice");
422
        }
423
        case super::ErrorKind::InvalidAlignmentValue(val) => {
424
            io::print("invalid alignment value: ");
425
            io::printU32(val);
426
        }
427
        case super::ErrorKind::InvalidModulePath => {
428
            io::print("invalid module path");
429
        }
430
        case super::ErrorKind::InvalidIdentifier(_) => {
431
            io::print("invalid identifier");
432
        }
433
        case super::ErrorKind::InvalidScopeAccess => {
434
            io::print("invalid scope access");
435
        }
436
        case super::ErrorKind::ArrayFieldUnknown(name) => {
437
            printQuoted("array field unknown: '", name);
438
        }
439
        case super::ErrorKind::SliceFieldUnknown(name) => {
440
            printQuoted("slice field unknown: '", name);
441
        }
442
        case super::ErrorKind::SliceRequiresAddress => {
443
            io::print("slicing requires taking an address with '&'");
444
        }
445
        case super::ErrorKind::SliceRangeOutOfBounds => {
446
            io::print("slice bounds exceed array length");
447
        }
448
        case super::ErrorKind::UnexpectedReturn => {
449
            io::print("unexpected return statement");
450
        }
451
        case super::ErrorKind::UnexpectedNode(n) => {
452
            io::print("unexpected expression");
453
        }
454
        case super::ErrorKind::PlaceholderExpression => {
455
            io::print("placeholder cannot be used as a value");
456
        }
457
        case super::ErrorKind::UnexpectedModuleName => {
458
            io::print("unexpected module name");
459
        }
460
        case super::ErrorKind::FnMissingBody => {
461
            io::print("function is missing a body");
462
        }
463
        case super::ErrorKind::FnUnexpectedBody => {
464
            io::print("function body is not expected");
465
        }
466
        case super::ErrorKind::IntrinsicUnexpectedBody => {
467
            io::print("intrinsic function must not have a body");
468
        }
469
        case super::ErrorKind::InvalidLoopControl => {
470
            io::print("loop control outside of a loop construct");
471
        }
472
        case super::ErrorKind::TryRequiresThrows => {
473
            io::print("try used when function does not declare throws");
474
        }
475
        case super::ErrorKind::TryIncompatibleError => {
476
            io::print("try propagates error not declared by function");
477
        }
478
        case super::ErrorKind::ThrowRequiresThrows => {
479
            io::print("throw used when function does not declare throws");
480
        }
481
        case super::ErrorKind::ThrowIncompatibleError => {
482
            io::print("throw uses error type not declared by function");
483
        }
484
        case super::ErrorKind::TryNonThrowing => {
485
            io::print("try applied to expression that cannot throw");
486
        }
487
        case super::ErrorKind::TryCatchMultiError => {
488
            io::print("catch with inferred binding requires single error type; use typed catches for multiple error types");
489
        }
490
        case super::ErrorKind::TryCatchDuplicateType => {
491
            io::print("duplicate error type in catch clauses");
492
        }
493
        case super::ErrorKind::AmbiguousRegionalError => {
494
            io::print("error types must remain distinct after region erasure");
495
        }
496
        case super::ErrorKind::TryCatchNonExhaustive => {
497
            io::print("catch clauses do not cover all error types");
498
        }
499
        case super::ErrorKind::MissingTry => {
500
            io::print("called fallible function without using try");
501
        }
502
        case super::ErrorKind::CannotInferType => {
503
            io::print("cannot infer type from context");
504
        }
505
        case super::ErrorKind::CannotAssignVoid => {
506
            io::print("cannot assign void value to a variable");
507
        }
508
        case super::ErrorKind::DefaultAttrOnlyOnFn => {
509
            io::print("default attribute can only be used on functions");
510
        }
511
        case super::ErrorKind::UnionVariantPayloadMissing(name) => {
512
            io::print("union variant '");
513
            io::print(name);
514
            io::print("' requires a payload");
515
        }
516
        case super::ErrorKind::UnionVariantPayloadUnexpected(name) => {
517
            io::print("union variant '");
518
            io::print(name);
519
            io::print("' does not expect a payload");
520
        }
521
        case super::ErrorKind::ReceiverMutabilityMismatch => {
522
            io::print("instance receiver mutability does not match trait declaration");
523
        }
524
        case super::ErrorKind::DuplicateInstance => {
525
            io::print("duplicate instance declaration for the same trait and type");
526
        }
527
        case super::ErrorKind::MissingTraitMethod(name) => {
528
            printQuoted("missing trait method '", name);
529
        }
530
        case super::ErrorKind::UnexpectedTraitName => {
531
            io::print("trait name cannot be used as a value");
532
        }
533
        case super::ErrorKind::TraitReceiverMismatch => {
534
            io::print("trait method receiver must be a pointer to the declaring trait");
535
        }
536
        case super::ErrorKind::TraitMethodSafetyMismatch => {
537
            io::print("trait method implementation has mismatched unsafe requirement");
538
        }
539
        case super::ErrorKind::FnParamOverflow(m) =>
540
            printMismatch("too many function parameters", "maximum", m),
541
        case super::ErrorKind::FnThrowOverflow(m) =>
542
            printMismatch("too many function throws", "maximum", m),
543
        case super::ErrorKind::TraitMethodOverflow(m) =>
544
            printMismatch("too many trait methods", "maximum", m),
545
        case super::ErrorKind::MissingSupertraitInstance(name) => {
546
            printQuoted("missing instance for supertrait '", name);
547
        }
548
        case super::ErrorKind::AffineUseAfterMove(name) => {
549
            printQuoted("affine value used after move: '", name);
550
        }
551
        case super::ErrorKind::LinearUseAfterConsume(name) => {
552
            printQuoted("linear value used after consumption: '", name);
553
        }
554
        case super::ErrorKind::LinearNotConsumed(name) => {
555
            printQuoted("linear value is not consumed: '", name);
556
        }
557
        case super::ErrorKind::LinearLetElseMustTerminate => {
558
            io::print("`let-else` fallback must terminate control flow");
559
        }
560
        case super::ErrorKind::LinearBranchMismatch(name) => {
561
            printQuoted("linear value has inconsistent branch state: '", name);
562
        }
563
        case super::ErrorKind::LinearPartialMove => {
564
            io::print("cannot move a field out of a linear value");
565
        }
566
        case super::ErrorKind::LinearDiscard => {
567
            io::print("linear value cannot be discarded");
568
        }
569
        case super::ErrorKind::LinearOverwrite => {
570
            io::print("assignment would overwrite a linear value");
571
        }
572
        case super::ErrorKind::LinearUndefined => {
573
            io::print("linear values cannot be undefined");
574
        }
575
        case super::ErrorKind::CopyContainsNonCopy => {
576
            io::print("`Copy` composite contains a non-copy value");
577
        }
578
        case super::ErrorKind::ConflictingOwnershipMarkers => {
579
            io::print("a composite cannot be both `Copy` and `Once`");
580
        }
581
        case super::ErrorKind::UnknownRegion(name) => {
582
            io::print("unknown region ");
583
            io::print(name);
584
        }
585
        case super::ErrorKind::RegionArgumentCount(count) => {
586
            printMismatch("region argument count", "expected", count);
587
        }
588
        case super::ErrorKind::RegionInference(name) => {
589
            io::print("cannot infer a consistent argument for region ");
590
            io::print(name);
591
        }
592
        case super::ErrorKind::RegionParent(name) => {
593
            io::print("region argument does not satisfy the parent relation for ");
594
            io::print(name);
595
        }
596
        case super::ErrorKind::RecursiveType => io::print("recursive value type has no finite layout"),
597
        case super::ErrorKind::RegionCycle(name) => {
598
            io::print("cyclic region parent relation for ");
599
            io::print(name);
600
        }
601
        case super::ErrorKind::InvalidRefPosition => {
602
            io::print("reference type is only allowed as a parameter or local binding");
603
        }
604
        case super::ErrorKind::RefBinding => {
605
            io::print("reference local requires an immutable binding to existing storage");
606
        }
607
        case super::ErrorKind::BorrowConflict(name) => {
608
            printQuoted("conflicting borrow of '", name);
609
        }
610
        case super::ErrorKind::UnsafeOperation => {
611
            io::print("unsafe operation requires an unsafe function or block");
612
        }
613
        case super::ErrorKind::UnsafeCall => {
614
            io::print("calling an unsafe function requires an unsafe function or block");
615
        }
616
        case super::ErrorKind::InvalidAllocationValue => {
617
            io::print("session allocation requires a value safe for bulk reclamation and plain Copy elements for slices");
618
        }
619
        case super::ErrorKind::InvalidAllocationLayout => {
620
            io::print("invalid or overflowing allocation layout");
621
        }
622
        case super::ErrorKind::InvalidAllocationRuntime => {
623
            io::print("invalid standard allocation trait signature");
624
        }
625
        case super::ErrorKind::InvalidCellPayload => {
626
            io::print("cell payload must be storable and bulk-discardable; unassociated cells also require Copy");
627
        }
628
        case super::ErrorKind::CellPermissionRequired(name) => {
629
            io::print("cell payload access requires matching authority for permission ");
630
            io::print(name);
631
        }
632
        case super::ErrorKind::InvalidSessionSource => {
633
            io::print("session requires one exclusive borrow of an std::lang::alloc::Alloc implementer");
634
        }
635
        case super::ErrorKind::RegionalLoanOverflow => io::print("too many simultaneous regional projections"),
636
        case super::ErrorKind::RegionEscape(name) => {
637
            io::print("value outlives region ");
638
            io::print(name);
639
        }
640
        case super::ErrorKind::Internal => {
641
            io::print("internal compiler error");
642
        }
643
        case super::ErrorKind::RecordFieldOutOfOrder { .. } => {
644
            io::print("record field out of order");
645
        }
646
        case super::ErrorKind::OpaqueTypeNotAllowed => {
647
            io::print("opaque type not allowed");
648
        }
649
        case super::ErrorKind::OpaqueRecordAccess => {
650
            io::print("opaque record representation is private to its defining module");
651
        }
652
        case super::ErrorKind::OpaqueTypeDeref => {
653
            io::print("opaque types cannot be dereferenced");
654
        }
655
        case super::ErrorKind::OpaquePointerArithmetic => {
656
            io::print("opaque pointer arithmetic is not allowed");
657
        }
658
        case super::ErrorKind::BuiltinArgCountMismatch { .. } => {
659
            io::print("built-in argument count mismatch");
660
        }
661
    }
662
    io::print("\n");
663
}
664
665
/// Entry point for printing resolver diagnostics in vim quickfix format.
666
export unsafe fn printDiagnostics 'arena 'permission (diag: &super::Diagnostics, res: &super::Resolver 'arena, graph: &module::ModuleGraph 'permission) {
667
    for i in 0..diag.errors.len {
668
        printError(&diag.errors[i], res, graph);
669
    }
670
}
671
672
/// Print an applied nominal type's explicit region arguments.
673
unsafe fn printNominalArguments(applied: *unsafe super::NominalApplication) {
674
    for region in applied.arguments {
675
        io::print(" ");
676
        io::print(region.name);
677
    }
678
}