authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-06 22:07:19-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-06 22:07:19-05:00
log634e8713c394bacfe080d03256d1dd4f9a43dd8c
tree8fa396aa96acfa556217f83eb90ecb6a14d88c4d
parentf0dafd3f209a342f055850108651545bea9b065b

add @memberType and @memberName builtin functions

see #383 there is a plan to unify most of the reflection into 2 builtin functions, as outlined in the above issue, but this gives us needed features for now, and we can iterate on the design in future commits

8 files changed, 440 insertions(+), 111 deletions(-)

src-self-hosted/main.zig-1
......@@ -5,7 +5,6 @@ const heap = @import("std").mem;
55
66// TODO: sync up CLI with c++ code
77// TODO: concurrency
8// TODO: ability to iterate over enums at compile time (for listing targets)
98
109error InvalidArgument;
1110error MissingArg0;
src/all_types.hpp+18
......@@ -1211,6 +1211,8 @@ enum BuiltinFnId {
12111211 BuiltinFnIdMaxValue,
12121212 BuiltinFnIdMinValue,
12131213 BuiltinFnIdMemberCount,
1214 BuiltinFnIdMemberType,
1215 BuiltinFnIdMemberName,
12141216 BuiltinFnIdTypeof,
12151217 BuiltinFnIdAddWithOverflow,
12161218 BuiltinFnIdSubWithOverflow,
......@@ -1845,6 +1847,8 @@ enum IrInstructionId {
18451847 IrInstructionIdMemcpy,
18461848 IrInstructionIdSlice,
18471849 IrInstructionIdMemberCount,
1850 IrInstructionIdMemberType,
1851 IrInstructionIdMemberName,
18481852 IrInstructionIdBreakpoint,
18491853 IrInstructionIdReturnAddress,
18501854 IrInstructionIdFrameAddress,
......@@ -2408,6 +2412,20 @@ struct IrInstructionMemberCount {
24082412 IrInstruction *container;
24092413};
24102414
2415struct IrInstructionMemberType {
2416 IrInstruction base;
2417
2418 IrInstruction *container_type;
2419 IrInstruction *member_index;
2420};
2421
2422struct IrInstructionMemberName {
2423 IrInstruction base;
2424
2425 IrInstruction *container_type;
2426 IrInstruction *member_index;
2427};
2428
24112429struct IrInstructionBreakpoint {
24122430 IrInstruction base;
24132431};
src/analyze.cpp+133-110
......@@ -1366,119 +1366,140 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
13661366 enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;
13671367 enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;
13681368
1369 if (!enum_type->data.enumeration.is_invalid) {
1370 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1371 TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
1372 enum_type->data.enumeration.tag_type = tag_type_entry;
1373
1374 uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1375
1376 if (most_aligned_union_member) {
1377 // create llvm type for union
1378 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
1379 LLVMTypeRef union_type_ref;
1380 if (padding_in_bits > 0) {
1381 TypeTableEntry *u8_type = get_int_type(g, false, 8);
1382 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1383 LLVMTypeRef union_element_types[] = {
1384 most_aligned_union_member->type_ref,
1385 padding_array->type_ref,
1386 };
1387 union_type_ref = LLVMStructType(union_element_types, 2, false);
1388 } else {
1389 union_type_ref = most_aligned_union_member->type_ref;
1390 }
1391 enum_type->data.enumeration.union_type_ref = union_type_ref;
1369 if (enum_type->data.enumeration.is_invalid)
1370 return;
13921371
1393 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
1394 assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
1372 if (enum_type->zero_bits) {
1373 enum_type->type_ref = LLVMVoidType();
13951374
1396 if (align_of_tag_in_bits >= biggest_align_in_bits) {
1397 enum_type->data.enumeration.gen_tag_index = 0;
1398 enum_type->data.enumeration.gen_union_index = 1;
1399 } else {
1400 enum_type->data.enumeration.gen_union_index = 0;
1401 enum_type->data.enumeration.gen_tag_index = 1;
1402 }
1375 uint64_t debug_size_in_bits = 0;
1376 uint64_t debug_align_in_bits = 0;
1377 ZigLLVMDIType **di_root_members = nullptr;
1378 size_t debug_member_count = 0;
1379 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1380 ZigLLVMFileToScope(import->di_file),
1381 buf_ptr(&enum_type->name),
1382 import->di_file, (unsigned)(decl_node->line + 1),
1383 debug_size_in_bits,
1384 debug_align_in_bits,
1385 0, nullptr, di_root_members, (int)debug_member_count, 0, nullptr, "");
14031386
1404 // create llvm type for root struct
1405 LLVMTypeRef root_struct_element_types[2];
1406 root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
1407 root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
1408 LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
1409
1410 // create debug type for tag
1411 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1412 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
1413 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1414 ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
1415 import->di_file, (unsigned)(decl_node->line + 1),
1416 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
1417 tag_type_entry->di_type, "");
1418
1419 // create debug type for union
1420 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1421 ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
1422 import->di_file, (unsigned)(decl_node->line + 1),
1423 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1424 gen_field_count, 0, "");
1425
1426 // create debug types for members of root struct
1427 uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1428 enum_type->data.enumeration.gen_tag_index);
1429 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1430 ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
1431 import->di_file, (unsigned)(decl_node->line + 1),
1432 tag_debug_size_in_bits,
1433 tag_debug_align_in_bits,
1434 tag_offset_in_bits,
1435 0, tag_di_type);
1436
1437 uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1438 enum_type->data.enumeration.gen_union_index);
1439 ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1440 ZigLLVMTypeToScope(enum_type->di_type), "union_field",
1441 import->di_file, (unsigned)(decl_node->line + 1),
1442 biggest_size_in_bits,
1443 biggest_align_in_bits,
1444 union_offset_in_bits,
1445 0, union_di_type);
1446
1447 // create debug type for root struct
1448 ZigLLVMDIType *di_root_members[2];
1449 di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
1450 di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
1451
1452 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
1453 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
1454 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1455 ZigLLVMFileToScope(import->di_file),
1456 buf_ptr(&enum_type->name),
1457 import->di_file, (unsigned)(decl_node->line + 1),
1458 debug_size_in_bits,
1459 debug_align_in_bits,
1460 0, nullptr, di_root_members, 2, 0, nullptr, "");
1461
1462 ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
1463 enum_type->di_type = replacement_di_type;
1387 ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
1388 enum_type->di_type = replacement_di_type;
1389 return;
1390 }
1391
1392 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1393 TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
1394 enum_type->data.enumeration.tag_type = tag_type_entry;
1395
1396 uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1397
1398 if (most_aligned_union_member) {
1399 // create llvm type for union
1400 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
1401 LLVMTypeRef union_type_ref;
1402 if (padding_in_bits > 0) {
1403 TypeTableEntry *u8_type = get_int_type(g, false, 8);
1404 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1405 LLVMTypeRef union_element_types[] = {
1406 most_aligned_union_member->type_ref,
1407 padding_array->type_ref,
1408 };
1409 union_type_ref = LLVMStructType(union_element_types, 2, false);
14641410 } else {
1465 // create llvm type for root struct
1466 enum_type->type_ref = tag_type_entry->type_ref;
1467
1468 // create debug type for tag
1469 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1470 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
1471 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1472 ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
1473 import->di_file, (unsigned)(decl_node->line + 1),
1474 tag_debug_size_in_bits,
1475 tag_debug_align_in_bits,
1476 di_enumerators, field_count,
1477 tag_type_entry->di_type, "");
1411 union_type_ref = most_aligned_union_member->type_ref;
1412 }
1413 enum_type->data.enumeration.union_type_ref = union_type_ref;
14781414
1479 ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
1480 enum_type->di_type = tag_di_type;
1415 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
1416 assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);
1417
1418 if (align_of_tag_in_bits >= biggest_align_in_bits) {
1419 enum_type->data.enumeration.gen_tag_index = 0;
1420 enum_type->data.enumeration.gen_union_index = 1;
1421 } else {
1422 enum_type->data.enumeration.gen_union_index = 0;
1423 enum_type->data.enumeration.gen_tag_index = 1;
14811424 }
1425
1426 // create llvm type for root struct
1427 LLVMTypeRef root_struct_element_types[2];
1428 root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;
1429 root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;
1430 LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);
1431
1432 // create debug type for tag
1433 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1434 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
1435 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1436 ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",
1437 import->di_file, (unsigned)(decl_node->line + 1),
1438 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,
1439 tag_type_entry->di_type, "");
1440
1441 // create debug type for union
1442 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,
1443 ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",
1444 import->di_file, (unsigned)(decl_node->line + 1),
1445 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,
1446 gen_field_count, 0, "");
1447
1448 // create debug types for members of root struct
1449 uint64_t tag_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1450 enum_type->data.enumeration.gen_tag_index);
1451 ZigLLVMDIType *tag_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1452 ZigLLVMTypeToScope(enum_type->di_type), "tag_field",
1453 import->di_file, (unsigned)(decl_node->line + 1),
1454 tag_debug_size_in_bits,
1455 tag_debug_align_in_bits,
1456 tag_offset_in_bits,
1457 0, tag_di_type);
1458
1459 uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, enum_type->type_ref,
1460 enum_type->data.enumeration.gen_union_index);
1461 ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder,
1462 ZigLLVMTypeToScope(enum_type->di_type), "union_field",
1463 import->di_file, (unsigned)(decl_node->line + 1),
1464 biggest_size_in_bits,
1465 biggest_align_in_bits,
1466 union_offset_in_bits,
1467 0, union_di_type);
1468
1469 // create debug type for root struct
1470 ZigLLVMDIType *di_root_members[2];
1471 di_root_members[enum_type->data.enumeration.gen_tag_index] = tag_member_di_type;
1472 di_root_members[enum_type->data.enumeration.gen_union_index] = union_member_di_type;
1473
1474 uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, enum_type->type_ref);
1475 uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, enum_type->type_ref);
1476 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1477 ZigLLVMFileToScope(import->di_file),
1478 buf_ptr(&enum_type->name),
1479 import->di_file, (unsigned)(decl_node->line + 1),
1480 debug_size_in_bits,
1481 debug_align_in_bits,
1482 0, nullptr, di_root_members, 2, 0, nullptr, "");
1483
1484 ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
1485 enum_type->di_type = replacement_di_type;
1486 } else {
1487 // create llvm type for root struct
1488 enum_type->type_ref = tag_type_entry->type_ref;
1489
1490 // create debug type for tag
1491 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);
1492 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);
1493 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,
1494 ZigLLVMFileToScope(import->di_file), buf_ptr(&enum_type->name),
1495 import->di_file, (unsigned)(decl_node->line + 1),
1496 tag_debug_size_in_bits,
1497 tag_debug_align_in_bits,
1498 di_enumerators, field_count,
1499 tag_type_entry->di_type, "");
1500
1501 ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);
1502 enum_type->di_type = tag_di_type;
14821503 }
14831504}
14841505
......@@ -1875,9 +1896,11 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
18751896 enum_type->data.enumeration.zero_bits_known = true;
18761897
18771898 // also compute abi_alignment
1878 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1879 uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1880 enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
1899 if (!enum_type->zero_bits) {
1900 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1901 uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1902 enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);
1903 }
18811904}
18821905
18831906static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {
src/codegen.cpp+4
......@@ -3384,6 +3384,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
33843384 case IrInstructionIdEmbedFile:
33853385 case IrInstructionIdIntType:
33863386 case IrInstructionIdMemberCount:
3387 case IrInstructionIdMemberType:
3388 case IrInstructionIdMemberName:
33873389 case IrInstructionIdAlignOf:
33883390 case IrInstructionIdFnProto:
33893391 case IrInstructionIdTestComptime:
......@@ -4867,6 +4869,8 @@ static void define_builtin_fns(CodeGen *g) {
48674869 create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1);
48684870 create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1);
48694871 create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
4872 create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
4873 create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
48704874 create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
48714875 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
48724876 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
src/ir.cpp+174
......@@ -411,6 +411,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) {
411411 return IrInstructionIdMemberCount;
412412}
413413
414static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberType *) {
415 return IrInstructionIdMemberType;
416}
417
418static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberName *) {
419 return IrInstructionIdMemberName;
420}
421
414422static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) {
415423 return IrInstructionIdBreakpoint;
416424}
......@@ -1783,6 +1791,32 @@ static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNod
17831791 return &instruction->base;
17841792}
17851793
1794static IrInstruction *ir_build_member_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
1795 IrInstruction *container_type, IrInstruction *member_index)
1796{
1797 IrInstructionMemberType *instruction = ir_build_instruction<IrInstructionMemberType>(irb, scope, source_node);
1798 instruction->container_type = container_type;
1799 instruction->member_index = member_index;
1800
1801 ir_ref_instruction(container_type, irb->current_basic_block);
1802 ir_ref_instruction(member_index, irb->current_basic_block);
1803
1804 return &instruction->base;
1805}
1806
1807static IrInstruction *ir_build_member_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
1808 IrInstruction *container_type, IrInstruction *member_index)
1809{
1810 IrInstructionMemberName *instruction = ir_build_instruction<IrInstructionMemberName>(irb, scope, source_node);
1811 instruction->container_type = container_type;
1812 instruction->member_index = member_index;
1813
1814 ir_ref_instruction(container_type, irb->current_basic_block);
1815 ir_ref_instruction(member_index, irb->current_basic_block);
1816
1817 return &instruction->base;
1818}
1819
17861820static IrInstruction *ir_build_breakpoint(IrBuilder *irb, Scope *scope, AstNode *source_node) {
17871821 IrInstructionBreakpoint *instruction = ir_build_instruction<IrInstructionBreakpoint>(irb, scope, source_node);
17881822 return &instruction->base;
......@@ -2727,6 +2761,22 @@ static IrInstruction *ir_instruction_membercount_get_dep(IrInstructionMemberCoun
27272761 }
27282762}
27292763
2764static IrInstruction *ir_instruction_membertype_get_dep(IrInstructionMemberType *instruction, size_t index) {
2765 switch (index) {
2766 case 0: return instruction->container_type;
2767 case 1: return instruction->member_index;
2768 default: return nullptr;
2769 }
2770}
2771
2772static IrInstruction *ir_instruction_membername_get_dep(IrInstructionMemberName *instruction, size_t index) {
2773 switch (index) {
2774 case 0: return instruction->container_type;
2775 case 1: return instruction->member_index;
2776 default: return nullptr;
2777 }
2778}
2779
27302780static IrInstruction *ir_instruction_breakpoint_get_dep(IrInstructionBreakpoint *instruction, size_t index) {
27312781 return nullptr;
27322782}
......@@ -3143,6 +3193,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
31433193 return ir_instruction_slice_get_dep((IrInstructionSlice *) instruction, index);
31443194 case IrInstructionIdMemberCount:
31453195 return ir_instruction_membercount_get_dep((IrInstructionMemberCount *) instruction, index);
3196 case IrInstructionIdMemberType:
3197 return ir_instruction_membertype_get_dep((IrInstructionMemberType *) instruction, index);
3198 case IrInstructionIdMemberName:
3199 return ir_instruction_membername_get_dep((IrInstructionMemberName *) instruction, index);
31463200 case IrInstructionIdBreakpoint:
31473201 return ir_instruction_breakpoint_get_dep((IrInstructionBreakpoint *) instruction, index);
31483202 case IrInstructionIdReturnAddress:
......@@ -4379,6 +4433,36 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
43794433
43804434 return ir_build_member_count(irb, scope, node, arg0_value);
43814435 }
4436 case BuiltinFnIdMemberType:
4437 {
4438 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4439 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4440 if (arg0_value == irb->codegen->invalid_instruction)
4441 return arg0_value;
4442
4443 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4444 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4445 if (arg1_value == irb->codegen->invalid_instruction)
4446 return arg1_value;
4447
4448
4449 return ir_build_member_type(irb, scope, node, arg0_value, arg1_value);
4450 }
4451 case BuiltinFnIdMemberName:
4452 {
4453 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4454 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4455 if (arg0_value == irb->codegen->invalid_instruction)
4456 return arg0_value;
4457
4458 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4459 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4460 if (arg1_value == irb->codegen->invalid_instruction)
4461 return arg1_value;
4462
4463
4464 return ir_build_member_name(irb, scope, node, arg0_value, arg1_value);
4465 }
43824466 case BuiltinFnIdBreakpoint:
43834467 return ir_build_breakpoint(irb, scope, node);
43844468 case BuiltinFnIdReturnAddress:
......@@ -14337,6 +14421,90 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
1433714421 return ira->codegen->builtin_types.entry_num_lit_int;
1433814422}
1433914423
14424static TypeTableEntry *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstructionMemberType *instruction) {
14425 IrInstruction *container_type_value = instruction->container_type->other;
14426 TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
14427 if (type_is_invalid(container_type))
14428 return ira->codegen->builtin_types.entry_invalid;
14429
14430 uint64_t member_index;
14431 IrInstruction *index_value = instruction->member_index->other;
14432 if (!ir_resolve_usize(ira, index_value, &member_index))
14433 return ira->codegen->builtin_types.entry_invalid;
14434
14435 if (container_type->id == TypeTableEntryIdStruct) {
14436 if (member_index >= container_type->data.structure.src_field_count) {
14437 ir_add_error(ira, index_value,
14438 buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
14439 member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count));
14440 return ira->codegen->builtin_types.entry_invalid;
14441 }
14442 TypeStructField *field = &container_type->data.structure.fields[member_index];
14443
14444 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14445 out_val->data.x_type = field->type_entry;
14446 return ira->codegen->builtin_types.entry_type;
14447 } else if (container_type->id == TypeTableEntryIdEnum) {
14448 if (member_index >= container_type->data.enumeration.src_field_count) {
14449 ir_add_error(ira, index_value,
14450 buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
14451 member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
14452 return ira->codegen->builtin_types.entry_invalid;
14453 }
14454 TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
14455
14456 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14457 out_val->data.x_type = field->type_entry;
14458 return ira->codegen->builtin_types.entry_type;
14459 } else {
14460 ir_add_error(ira, container_type_value,
14461 buf_sprintf("type '%s' does not support @memberType", buf_ptr(&container_type->name)));
14462 return ira->codegen->builtin_types.entry_invalid;
14463 }
14464}
14465
14466static TypeTableEntry *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstructionMemberName *instruction) {
14467 IrInstruction *container_type_value = instruction->container_type->other;
14468 TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value);
14469 if (type_is_invalid(container_type))
14470 return ira->codegen->builtin_types.entry_invalid;
14471
14472 uint64_t member_index;
14473 IrInstruction *index_value = instruction->member_index->other;
14474 if (!ir_resolve_usize(ira, index_value, &member_index))
14475 return ira->codegen->builtin_types.entry_invalid;
14476
14477 if (container_type->id == TypeTableEntryIdStruct) {
14478 if (member_index >= container_type->data.structure.src_field_count) {
14479 ir_add_error(ira, index_value,
14480 buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
14481 member_index, buf_ptr(&container_type->name), container_type->data.structure.src_field_count));
14482 return ira->codegen->builtin_types.entry_invalid;
14483 }
14484 TypeStructField *field = &container_type->data.structure.fields[member_index];
14485
14486 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14487 init_const_str_lit(ira->codegen, out_val, field->name);
14488 return out_val->type;
14489 } else if (container_type->id == TypeTableEntryIdEnum) {
14490 if (member_index >= container_type->data.enumeration.src_field_count) {
14491 ir_add_error(ira, index_value,
14492 buf_sprintf("member index %" ZIG_PRI_u64 " out of bounds; '%s' has %" PRIu32 " members",
14493 member_index, buf_ptr(&container_type->name), container_type->data.enumeration.src_field_count));
14494 return ira->codegen->builtin_types.entry_invalid;
14495 }
14496 TypeEnumField *field = &container_type->data.enumeration.fields[member_index];
14497
14498 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
14499 init_const_str_lit(ira->codegen, out_val, field->name);
14500 return out_val->type;
14501 } else {
14502 ir_add_error(ira, container_type_value,
14503 buf_sprintf("type '%s' does not support @memberName", buf_ptr(&container_type->name)));
14504 return ira->codegen->builtin_types.entry_invalid;
14505 }
14506}
14507
1434014508static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) {
1434114509 ir_build_breakpoint_from(&ira->new_irb, &instruction->base);
1434214510 return ira->codegen->builtin_types.entry_void;
......@@ -15606,6 +15774,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1560615774 return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);
1560715775 case IrInstructionIdMemberCount:
1560815776 return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction);
15777 case IrInstructionIdMemberType:
15778 return ir_analyze_instruction_member_type(ira, (IrInstructionMemberType *)instruction);
15779 case IrInstructionIdMemberName:
15780 return ir_analyze_instruction_member_name(ira, (IrInstructionMemberName *)instruction);
1560915781 case IrInstructionIdBreakpoint:
1561015782 return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction);
1561115783 case IrInstructionIdReturnAddress:
......@@ -15815,6 +15987,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1581515987 case IrInstructionIdBoolNot:
1581615988 case IrInstructionIdSlice:
1581715989 case IrInstructionIdMemberCount:
15990 case IrInstructionIdMemberType:
15991 case IrInstructionIdMemberName:
1581815992 case IrInstructionIdAlignOf:
1581915993 case IrInstructionIdReturnAddress:
1582015994 case IrInstructionIdFrameAddress:
src/ir_print.cpp+22
......@@ -658,6 +658,22 @@ static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instru
658658 fprintf(irp->f, ")");
659659}
660660
661static void ir_print_member_type(IrPrint *irp, IrInstructionMemberType *instruction) {
662 fprintf(irp->f, "@memberType(");
663 ir_print_other_instruction(irp, instruction->container_type);
664 fprintf(irp->f, ", ");
665 ir_print_other_instruction(irp, instruction->member_index);
666 fprintf(irp->f, ")");
667}
668
669static void ir_print_member_name(IrPrint *irp, IrInstructionMemberName *instruction) {
670 fprintf(irp->f, "@memberName(");
671 ir_print_other_instruction(irp, instruction->container_type);
672 fprintf(irp->f, ", ");
673 ir_print_other_instruction(irp, instruction->member_index);
674 fprintf(irp->f, ")");
675}
676
661677static void ir_print_breakpoint(IrPrint *irp, IrInstructionBreakpoint *instruction) {
662678 fprintf(irp->f, "@breakpoint()");
663679}
......@@ -1148,6 +1164,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
11481164 case IrInstructionIdMemberCount:
11491165 ir_print_member_count(irp, (IrInstructionMemberCount *)instruction);
11501166 break;
1167 case IrInstructionIdMemberType:
1168 ir_print_member_type(irp, (IrInstructionMemberType *)instruction);
1169 break;
1170 case IrInstructionIdMemberName:
1171 ir_print_member_name(irp, (IrInstructionMemberName *)instruction);
1172 break;
11511173 case IrInstructionIdBreakpoint:
11521174 ir_print_breakpoint(irp, (IrInstructionBreakpoint *)instruction);
11531175 break;
test/cases/reflection.zig+43
......@@ -25,3 +25,46 @@ test "reflection: function return type, var args, and param types" {
2525fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }
2626fn dummy_varargs(args: ...) {}
2727
28test "reflection: struct member types and names" {
29 comptime {
30 assert(@memberCount(Foo) == 3);
31
32 assert(@memberType(Foo, 0) == i32);
33 assert(@memberType(Foo, 1) == bool);
34 assert(@memberType(Foo, 2) == void);
35
36 assert(mem.eql(u8, @memberName(Foo, 0), "one"));
37 assert(mem.eql(u8, @memberName(Foo, 1), "two"));
38 assert(mem.eql(u8, @memberName(Foo, 2), "three"));
39 }
40}
41
42test "reflection: enum member types and names" {
43 comptime {
44 assert(@memberCount(Bar) == 4);
45
46 assert(@memberType(Bar, 0) == void);
47 assert(@memberType(Bar, 1) == i32);
48 assert(@memberType(Bar, 2) == bool);
49 assert(@memberType(Bar, 3) == f64);
50
51 assert(mem.eql(u8, @memberName(Bar, 0), "One"));
52 assert(mem.eql(u8, @memberName(Bar, 1), "Two"));
53 assert(mem.eql(u8, @memberName(Bar, 2), "Three"));
54 assert(mem.eql(u8, @memberName(Bar, 3), "Four"));
55 }
56
57}
58
59const Foo = struct {
60 one: i32,
61 two: bool,
62 three: void,
63};
64
65const Bar = enum {
66 One,
67 Two: i32,
68 Three: bool,
69 Four: f64,
70};
test/compile_errors.zig+46
......@@ -2289,4 +2289,50 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
22892289 \\fn add(a: i32, b: i32) -> i32 { return a + b; }
22902290 ,
22912291 ".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) -> i32' has 2 arguments");
2292
2293 cases.add("@memberType on unsupported type",
2294 \\comptime {
2295 \\ _ = @memberType(i32, 0);
2296 \\}
2297 ,
2298 ".tmp_source.zig:2:21: error: type 'i32' does not support @memberType");
2299
2300 cases.add("@memberType struct out of bounds",
2301 \\comptime {
2302 \\ _ = @memberType(Foo, 0);
2303 \\}
2304 \\const Foo = struct {};
2305 ,
2306 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
2307
2308 cases.add("@memberType enum out of bounds",
2309 \\comptime {
2310 \\ _ = @memberType(Foo, 0);
2311 \\}
2312 \\const Foo = enum {};
2313 ,
2314 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
2315
2316 cases.add("@memberName on unsupported type",
2317 \\comptime {
2318 \\ _ = @memberName(i32, 0);
2319 \\}
2320 ,
2321 ".tmp_source.zig:2:21: error: type 'i32' does not support @memberName");
2322
2323 cases.add("@memberName struct out of bounds",
2324 \\comptime {
2325 \\ _ = @memberName(Foo, 0);
2326 \\}
2327 \\const Foo = struct {};
2328 ,
2329 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
2330
2331 cases.add("@memberName enum out of bounds",
2332 \\comptime {
2333 \\ _ = @memberName(Foo, 0);
2334 \\}
2335 \\const Foo = enum {};
2336 ,
2337 ".tmp_source.zig:2:26: error: member index 0 out of bounds; 'Foo' has 0 members");
22922338}