const Loc = union(enum) discard: discardThe expression is the right-hand side of assignment to _. Only the side-effects of the expression should be generated. The result instruction from the expression must be ignored.
none: noneThe expression has an inferred type, and it will be evaluated as an rvalue.
ty: Zir.Inst.RefThe expression will be coerced into this type, but it will be evaluated as an rvalue.
coerced_ty: Zir.Inst.RefSame as ty but it is guaranteed that Sema will additionally perform the coercion, so no as instruction needs to be emitted.
ref: refThe expression must generate a pointer rather than a value. For example, the left hand side of an assignment uses this kind of result location.
ref_coerced_ty: Zir.Inst.RefThe expression must generate a pointer rather than a value, and the pointer will be coerced by other code to this type, which is guaranteed by earlier instructions to be a pointer type.
ref_const: ref_constLike ref, but the pointer will never be stored to, so local variables should not be marked as possibly being mutated.
ptr: PtrResultLocThe expression must store its result into this typed pointer. The result instruction from the expression must be ignored.
inferred_ptr: Zir.Inst.RefThe expression must store its result into this allocation, which has an inferred type. The result instruction from the expression must be ignored. Always an instruction with tag alloc_inferred.
destructure: struct { /// The AST node of the destructure operation itself. src_node: Ast.Node.Index, /// The pointers to store results into. components: []const DestructureComponent, }The expression has a sequence of pointers to store its results into due to a destructure operation. Each of these pointers may or may not have an inferred type.
fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index) !?Zir.Inst.RefFind the result type for a cast builtin given the result location. If the location does not have a known result type, returns null.
fn resultTypeForCast(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.RefFind the result type for a cast builtin given the result location. If the location does not have a known result type, emits an error on the given node.
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374 const Loc = union(enum) {
/// The expression is the right-hand side of assignment to `_`. Only the side-effects of the
/// expression should be generated. The result instruction from the expression must
/// be ignored.
discard,
/// The expression has an inferred type, and it will be evaluated as an rvalue.
none,
/// The expression will be coerced into this type, but it will be evaluated as an rvalue.
ty: Zir.Inst.Ref,
/// Same as `ty` but it is guaranteed that Sema will additionally perform the coercion,
/// so no `as` instruction needs to be emitted.
coerced_ty: Zir.Inst.Ref,
/// The expression must generate a pointer rather than a value. For example, the left hand side
/// of an assignment uses this kind of result location.
ref,
/// The expression must generate a pointer rather than a value, and the pointer will be coerced
/// by other code to this type, which is guaranteed by earlier instructions to be a pointer type.
ref_coerced_ty: Zir.Inst.Ref,
/// Like `ref`, but the pointer will never be stored to, so local variables should not be
/// marked as possibly being mutated.
ref_const,
/// The expression must store its result into this typed pointer. The result instruction
/// from the expression must be ignored.
ptr: PtrResultLoc,
/// The expression must store its result into this allocation, which has an inferred type.
/// The result instruction from the expression must be ignored.
/// Always an instruction with tag `alloc_inferred`.
inferred_ptr: Zir.Inst.Ref,
/// The expression has a sequence of pointers to store its results into due to a destructure
/// operation. Each of these pointers may or may not have an inferred type.
destructure: struct {
/// The AST node of the destructure operation itself.
src_node: Ast.Node.Index,
/// The pointers to store results into.
components: []const DestructureComponent,
},
const DestructureComponent = union(enum) {
typed_ptr: PtrResultLoc,
inferred_ptr: Zir.Inst.Ref,
discard,
};
const PtrResultLoc = struct {
inst: Zir.Inst.Ref,
src_node: ?Ast.Node.Index = null,
};
/// Find the result type for a cast builtin given the result location.
/// If the location does not have a known result type, returns `null`.
fn resultType(rl: Loc, gz: *GenZir, node: Ast.Node.Index) !?Zir.Inst.Ref {
return switch (rl) {
.discard, .none, .ref, .ref_const, .inferred_ptr, .destructure => null,
.ty, .coerced_ty => |ty_ref| ty_ref,
.ref_coerced_ty => |ptr_ty| try gz.addUnNode(.elem_type, ptr_ty, node),
.ptr => |ptr| {
const ptr_ty = try gz.addUnNode(.typeof, ptr.inst, node);
return try gz.addUnNode(.elem_type, ptr_ty, node);
},
};
}
/// Find the result type for a cast builtin given the result location.
/// If the location does not have a known result type, emits an error on
/// the given node.
fn resultTypeForCast(rl: Loc, gz: *GenZir, node: Ast.Node.Index, builtin_name: []const u8) !Zir.Inst.Ref {
const astgen = gz.astgen;
if (try rl.resultType(gz, node)) |ty| return ty;
switch (rl) {
.destructure => |destructure| return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
try astgen.errNoteNode(destructure.src_node, "destructure expressions do not provide a single result type", .{}),
try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
}),
else => return astgen.failNodeNotes(node, "{s} must have a known result type", .{builtin_name}, &.{
try astgen.errNoteNode(node, "use @as to provide explicit result type", .{}),
}),
}
}
}