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