| ... | @@ -15724,7 +15724,7 @@ fn tupleField( | ... | @@ -15724,7 +15724,7 @@ fn tupleField( |
| 15724 | field_index_src: LazySrcLoc, | 15724 | field_index_src: LazySrcLoc, |
| 15725 | ) CompileError!Air.Inst.Ref { | 15725 | ) CompileError!Air.Inst.Ref { |
| 15726 | const tuple_ty = sema.typeOf(tuple); | 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 | if (field_index > tuple_info.types.len) { | 15729 | if (field_index > tuple_info.types.len) { |
| 15730 | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ | 15730 | return sema.fail(block, field_index_src, "index {d} outside tuple of length {d}", .{ |
| ... | @@ -16195,6 +16195,9 @@ fn coerce( | ... | @@ -16195,6 +16195,9 @@ fn coerce( |
| 16195 | if (inst == .empty_struct) { | 16195 | if (inst == .empty_struct) { |
| 16196 | return structInitEmpty(sema, block, dest_ty, dest_ty_src, inst_src); | 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 | else => {}, | 16202 | else => {}, |
| 16200 | } | 16203 | } |
| ... | @@ -17442,6 +17445,94 @@ fn coerceTupleToArray( | ... | @@ -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 | fn analyzeDeclVal( | 17536 | fn analyzeDeclVal( |
| 17446 | sema: *Sema, | 17537 | sema: *Sema, |
| 17447 | block: *Block, | 17538 | block: *Block, |
| ... | @@ -20365,3 +20456,17 @@ fn unionFieldIndex( | ... | @@ -20365,3 +20456,17 @@ fn unionFieldIndex( |
| 20365 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); | 20456 | return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name); |
| 20366 | return @intCast(u32, field_index_usize); | 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 | } |