| ... | ... | @@ -15724,7 +15724,7 @@ fn tupleField( |
| 15724 | 15724 | field_index_src: LazySrcLoc, |
| 15725 | 15725 | ) CompileError!Air.Inst.Ref { |
| 15726 | 15726 | const tuple_ty = sema.typeOf(tuple); |
| 15727 | | const tuple_info = tuple_ty.castTag(.tuple).?.data; |
| 15727 | const tuple_info = tuple_ty.tupleFields(); |
| 15728 | 15728 | |
| 15729 | 15729 | if (field_index > tuple_info.types.len) { |
| 15730 | 15730 | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ |
| ... | ... | @@ -16195,6 +16195,9 @@ fn coerce( |
| 16195 | 16195 | if (inst == .empty_struct) { |
| 16196 | 16196 | return structInitEmpty(sema, block, dest_ty, dest_ty_src, inst_src); |
| 16197 | 16197 | } |
| 16198 | if (inst_ty.isTupleOrAnonStruct()) { |
| 16199 | return sema.coerceTupleToStruct(block, dest_ty, dest_ty_src, inst, inst_src); |
| 16200 | } |
| 16198 | 16201 | }, |
| 16199 | 16202 | else => {}, |
| 16200 | 16203 | } |
| ... | ... | @@ -17442,6 +17445,94 @@ fn coerceTupleToArray( |
| 17442 | 17445 | ); |
| 17443 | 17446 | } |
| 17444 | 17447 | |
| 17448 | /// Handles both tuples and anon struct literals. Coerces field-wise. Reports |
| 17449 | /// errors for both extra fields and missing fields. |
| 17450 | fn coerceTupleToStruct( |
| 17451 | sema: *Sema, |
| 17452 | block: *Block, |
| 17453 | dest_ty: Type, |
| 17454 | dest_ty_src: LazySrcLoc, |
| 17455 | inst: Air.Inst.Ref, |
| 17456 | inst_src: LazySrcLoc, |
| 17457 | ) !Air.Inst.Ref { |
| 17458 | if (dest_ty.isTupleOrAnonStruct()) { |
| 17459 | return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to tuples", .{}); |
| 17460 | } |
| 17461 | |
| 17462 | const fields = dest_ty.structFields(); |
| 17463 | const field_vals = try sema.arena.alloc(Value, fields.count()); |
| 17464 | const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len); |
| 17465 | mem.set(Air.Inst.Ref, field_refs, .none); |
| 17466 | |
| 17467 | const inst_ty = sema.typeOf(inst); |
| 17468 | const tuple = inst_ty.tupleFields(); |
| 17469 | var runtime_src: ?LazySrcLoc = null; |
| 17470 | for (tuple.types) |_, i_usize| { |
| 17471 | const i = @intCast(u32, i_usize); |
| 17472 | const field_src = inst_src; // TODO better source location |
| 17473 | const field_name = if (inst_ty.castTag(.anon_struct)) |payload| |
| 17474 | payload.data.names[i] |
| 17475 | else |
| 17476 | try std.fmt.allocPrint(sema.arena, "{d}", .{i}); |
| 17477 | const field_index = try sema.structFieldIndex(block, dest_ty, field_name, field_src); |
| 17478 | const field = fields.values()[field_index]; |
| 17479 | if (field.is_comptime) { |
| 17480 | return sema.fail(block, dest_ty_src, "TODO: implement coercion from tuples to structs when one of the destination struct fields is comptime", .{}); |
| 17481 | } |
| 17482 | const elem_ref = try tupleField(sema, block, inst, i, inst_src, field_src); |
| 17483 | const coerced = try sema.coerce(block, field.ty, elem_ref, field_src); |
| 17484 | field_refs[field_index] = coerced; |
| 17485 | if (runtime_src == null) { |
| 17486 | if (try sema.resolveMaybeUndefVal(block, field_src, coerced)) |field_val| { |
| 17487 | field_vals[field_index] = field_val; |
| 17488 | } else { |
| 17489 | runtime_src = field_src; |
| 17490 | } |
| 17491 | } |
| 17492 | } |
| 17493 | |
| 17494 | // Populate default field values and report errors for missing fields. |
| 17495 | var root_msg: ?*Module.ErrorMsg = null; |
| 17496 | |
| 17497 | for (field_refs) |*field_ref, i| { |
| 17498 | if (field_ref.* != .none) continue; |
| 17499 | |
| 17500 | const field_name = fields.keys()[i]; |
| 17501 | const field = fields.values()[i]; |
| 17502 | const field_src = inst_src; // TODO better source location |
| 17503 | if (field.default_val.tag() == .unreachable_value) { |
| 17504 | const template = "missing struct field: {s}"; |
| 17505 | const args = .{field_name}; |
| 17506 | if (root_msg) |msg| { |
| 17507 | try sema.errNote(block, field_src, msg, template, args); |
| 17508 | } else { |
| 17509 | root_msg = try sema.errMsg(block, field_src, template, args); |
| 17510 | } |
| 17511 | continue; |
| 17512 | } |
| 17513 | if (runtime_src == null) { |
| 17514 | field_vals[i] = field.default_val; |
| 17515 | } else { |
| 17516 | field_ref.* = try sema.addConstant(field.ty, field.default_val); |
| 17517 | } |
| 17518 | } |
| 17519 | |
| 17520 | if (root_msg) |msg| { |
| 17521 | try sema.addDeclaredHereNote(msg, dest_ty); |
| 17522 | return sema.failWithOwnedErrorMsg(block, msg); |
| 17523 | } |
| 17524 | |
| 17525 | if (runtime_src) |rs| { |
| 17526 | try sema.requireRuntimeBlock(block, rs); |
| 17527 | return block.addAggregateInit(dest_ty, field_refs); |
| 17528 | } |
| 17529 | |
| 17530 | return sema.addConstant( |
| 17531 | dest_ty, |
| 17532 | try Value.Tag.@"struct".create(sema.arena, field_vals), |
| 17533 | ); |
| 17534 | } |
| 17535 | |
| 17445 | 17536 | fn analyzeDeclVal( |
| 17446 | 17537 | sema: *Sema, |
| 17447 | 17538 | block: *Block, |
| ... | ... | @@ -20365,3 +20456,17 @@ fn unionFieldIndex( |
| 20365 | 20456 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); |
| 20366 | 20457 | return @intCast(u32, field_index_usize); |
| 20367 | 20458 | } |
| 20459 | |
| 20460 | fn structFieldIndex( |
| 20461 | sema: *Sema, |
| 20462 | block: *Block, |
| 20463 | unresolved_struct_ty: Type, |
| 20464 | field_name: []const u8, |
| 20465 | field_src: LazySrcLoc, |
| 20466 | ) !u32 { |
| 20467 | const struct_ty = try sema.resolveTypeFields(block, field_src, unresolved_struct_ty); |
| 20468 | const struct_obj = struct_ty.castTag(.@"struct").?.data; |
| 20469 | const field_index_usize = struct_obj.fields.getIndex(field_name) orelse |
| 20470 | return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name); |
| 20471 | return @intCast(u32, field_index_usize); |
| 20472 | } |