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;...@@ -5,7 +5,6 @@ const heap = @import("std").mem;
55
6// TODO: sync up CLI with c++ code6// TODO: sync up CLI with c++ code
7// TODO: concurrency7// TODO: concurrency
8// TODO: ability to iterate over enums at compile time (for listing targets)
98
10error InvalidArgument;9error InvalidArgument;
11error MissingArg0;10error MissingArg0;
src/all_types.hpp+18
...@@ -1211,6 +1211,8 @@ enum BuiltinFnId {...@@ -1211,6 +1211,8 @@ enum BuiltinFnId {
1211 BuiltinFnIdMaxValue,1211 BuiltinFnIdMaxValue,
1212 BuiltinFnIdMinValue,1212 BuiltinFnIdMinValue,
1213 BuiltinFnIdMemberCount,1213 BuiltinFnIdMemberCount,
1214 BuiltinFnIdMemberType,
1215 BuiltinFnIdMemberName,
1214 BuiltinFnIdTypeof,1216 BuiltinFnIdTypeof,
1215 BuiltinFnIdAddWithOverflow,1217 BuiltinFnIdAddWithOverflow,
1216 BuiltinFnIdSubWithOverflow,1218 BuiltinFnIdSubWithOverflow,
...@@ -1845,6 +1847,8 @@ enum IrInstructionId {...@@ -1845,6 +1847,8 @@ enum IrInstructionId {
1845 IrInstructionIdMemcpy,1847 IrInstructionIdMemcpy,
1846 IrInstructionIdSlice,1848 IrInstructionIdSlice,
1847 IrInstructionIdMemberCount,1849 IrInstructionIdMemberCount,
1850 IrInstructionIdMemberType,
1851 IrInstructionIdMemberName,
1848 IrInstructionIdBreakpoint,1852 IrInstructionIdBreakpoint,
1849 IrInstructionIdReturnAddress,1853 IrInstructionIdReturnAddress,
1850 IrInstructionIdFrameAddress,1854 IrInstructionIdFrameAddress,
...@@ -2408,6 +2412,20 @@ struct IrInstructionMemberCount {...@@ -2408,6 +2412,20 @@ struct IrInstructionMemberCount {
2408 IrInstruction *container;2412 IrInstruction *container;
2409};2413};
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
2411struct IrInstructionBreakpoint {2429struct IrInstructionBreakpoint {
2412 IrInstruction base;2430 IrInstruction base;
2413};2431};
src/analyze.cpp+133-110
...@@ -1366,119 +1366,140 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1366,119 +1366,140 @@ static void resolve_enum_type(CodeGen *g, TypeTableEntry *enum_type) {
1366 enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;1366 enum_type->data.enumeration.union_size_bytes = biggest_size_in_bits / 8;
1367 enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;1367 enum_type->data.enumeration.most_aligned_union_member = most_aligned_union_member;
13681368
1369 if (!enum_type->data.enumeration.is_invalid) {1369 if (enum_type->data.enumeration.is_invalid)
1370 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);1370 return;
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;
13921371
1393 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);1372 if (enum_type->zero_bits) {
1394 assert(8*LLVMStoreSizeOfType(g->target_data_ref, union_type_ref) >= biggest_size_in_bits);1373 enum_type->type_ref = LLVMVoidType();
13951374
1396 if (align_of_tag_in_bits >= biggest_align_in_bits) {1375 uint64_t debug_size_in_bits = 0;
1397 enum_type->data.enumeration.gen_tag_index = 0;1376 uint64_t debug_align_in_bits = 0;
1398 enum_type->data.enumeration.gen_union_index = 1;1377 ZigLLVMDIType **di_root_members = nullptr;
1399 } else {1378 size_t debug_member_count = 0;
1400 enum_type->data.enumeration.gen_union_index = 0;1379 ZigLLVMDIType *replacement_di_type = ZigLLVMCreateDebugStructType(g->dbuilder,
1401 enum_type->data.enumeration.gen_tag_index = 1;1380 ZigLLVMFileToScope(import->di_file),
1402 }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 struct1387 ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, replacement_di_type);
1405 LLVMTypeRef root_struct_element_types[2];1388 enum_type->di_type = replacement_di_type;
1406 root_struct_element_types[enum_type->data.enumeration.gen_tag_index] = tag_type_entry->type_ref;1389 return;
1407 root_struct_element_types[enum_type->data.enumeration.gen_union_index] = union_type_ref;1390 }
1408 LLVMStructSetBody(enum_type->type_ref, root_struct_element_types, 2, false);1391
14091392 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1410 // create debug type for tag1393 TypeTableEntry *tag_type_entry = create_enum_tag_type(g, enum_type, tag_int_type);
1411 uint64_t tag_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, tag_type_entry->type_ref);1394 enum_type->data.enumeration.tag_type = tag_type_entry;
1412 uint64_t tag_debug_align_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_type_entry->type_ref);1395
1413 ZigLLVMDIType *tag_di_type = ZigLLVMCreateDebugEnumerationType(g->dbuilder,1396 uint64_t align_of_tag_in_bits = 8*LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);
1414 ZigLLVMTypeToScope(enum_type->di_type), "AnonEnum",1397
1415 import->di_file, (unsigned)(decl_node->line + 1),1398 if (most_aligned_union_member) {
1416 tag_debug_size_in_bits, tag_debug_align_in_bits, di_enumerators, field_count,1399 // create llvm type for union
1417 tag_type_entry->di_type, "");1400 uint64_t padding_in_bits = biggest_size_in_bits - size_of_most_aligned_member_in_bits;
14181401 LLVMTypeRef union_type_ref;
1419 // create debug type for union1402 if (padding_in_bits > 0) {
1420 ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder,1403 TypeTableEntry *u8_type = get_int_type(g, false, 8);
1421 ZigLLVMTypeToScope(enum_type->di_type), "AnonUnion",1404 TypeTableEntry *padding_array = get_array_type(g, u8_type, padding_in_bits / 8);
1422 import->di_file, (unsigned)(decl_node->line + 1),1405 LLVMTypeRef union_element_types[] = {
1423 biggest_size_in_bits, biggest_align_in_bits, 0, union_inner_di_types,1406 most_aligned_union_member->type_ref,
1424 gen_field_count, 0, "");1407 padding_array->type_ref,
14251408 };
1426 // create debug types for members of root struct1409 union_type_ref = LLVMStructType(union_element_types, 2, false);
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;
1464 } else {1410 } else {
1465 // create llvm type for root struct1411 union_type_ref = most_aligned_union_member->type_ref;
1466 enum_type->type_ref = tag_type_entry->type_ref;1412 }
14671413 enum_type->data.enumeration.union_type_ref = union_type_ref;
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, "");
14781414
1479 ZigLLVMReplaceTemporary(g->dbuilder, enum_type->di_type, tag_di_type);1415 assert(8*LLVMABIAlignmentOfType(g->target_data_ref, union_type_ref) >= biggest_align_in_bits);
1480 enum_type->di_type = tag_di_type;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;
1481 }1424 }
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;
1482 }1503 }
1483}1504}
14841505
...@@ -1875,9 +1896,11 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {...@@ -1875,9 +1896,11 @@ static void resolve_enum_zero_bits(CodeGen *g, TypeTableEntry *enum_type) {
1875 enum_type->data.enumeration.zero_bits_known = true;1896 enum_type->data.enumeration.zero_bits_known = true;
18761897
1877 // also compute abi_alignment1898 // also compute abi_alignment
1878 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);1899 if (!enum_type->zero_bits) {
1879 uint32_t align_of_tag_in_bytes = LLVMABIAlignmentOfType(g->target_data_ref, tag_int_type->type_ref);1900 TypeTableEntry *tag_int_type = get_smallest_unsigned_int_type(g, field_count);
1880 enum_type->data.enumeration.abi_alignment = max(align_of_tag_in_bytes, biggest_align_bytes);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 }
1881}1904}
18821905
1883static void resolve_struct_zero_bits(CodeGen *g, TypeTableEntry *struct_type) {1906static 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,...@@ -3384,6 +3384,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
3384 case IrInstructionIdEmbedFile:3384 case IrInstructionIdEmbedFile:
3385 case IrInstructionIdIntType:3385 case IrInstructionIdIntType:
3386 case IrInstructionIdMemberCount:3386 case IrInstructionIdMemberCount:
3387 case IrInstructionIdMemberType:
3388 case IrInstructionIdMemberName:
3387 case IrInstructionIdAlignOf:3389 case IrInstructionIdAlignOf:
3388 case IrInstructionIdFnProto:3390 case IrInstructionIdFnProto:
3389 case IrInstructionIdTestComptime:3391 case IrInstructionIdTestComptime:
...@@ -4867,6 +4869,8 @@ static void define_builtin_fns(CodeGen *g) {...@@ -4867,6 +4869,8 @@ static void define_builtin_fns(CodeGen *g) {
4867 create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1);4869 create_builtin_fn(g, BuiltinFnIdMaxValue, "maxValue", 1);
4868 create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1);4870 create_builtin_fn(g, BuiltinFnIdMinValue, "minValue", 1);
4869 create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);4871 create_builtin_fn(g, BuiltinFnIdMemberCount, "memberCount", 1);
4872 create_builtin_fn(g, BuiltinFnIdMemberType, "memberType", 2);
4873 create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2);
4870 create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf4874 create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf
4871 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);4875 create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4);
4872 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);4876 create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4);
src/ir.cpp+174
...@@ -411,6 +411,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) {...@@ -411,6 +411,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) {
411 return IrInstructionIdMemberCount;411 return IrInstructionIdMemberCount;
412}412}
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
414static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) {422static constexpr IrInstructionId ir_instruction_id(IrInstructionBreakpoint *) {
415 return IrInstructionIdBreakpoint;423 return IrInstructionIdBreakpoint;
416}424}
...@@ -1783,6 +1791,32 @@ static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNod...@@ -1783,6 +1791,32 @@ static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNod
1783 return &instruction->base;1791 return &instruction->base;
1784}1792}
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
1786static IrInstruction *ir_build_breakpoint(IrBuilder *irb, Scope *scope, AstNode *source_node) {1820static IrInstruction *ir_build_breakpoint(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1787 IrInstructionBreakpoint *instruction = ir_build_instruction<IrInstructionBreakpoint>(irb, scope, source_node);1821 IrInstructionBreakpoint *instruction = ir_build_instruction<IrInstructionBreakpoint>(irb, scope, source_node);
1788 return &instruction->base;1822 return &instruction->base;
...@@ -2727,6 +2761,22 @@ static IrInstruction *ir_instruction_membercount_get_dep(IrInstructionMemberCoun...@@ -2727,6 +2761,22 @@ static IrInstruction *ir_instruction_membercount_get_dep(IrInstructionMemberCoun
2727 }2761 }
2728}2762}
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
2730static IrInstruction *ir_instruction_breakpoint_get_dep(IrInstructionBreakpoint *instruction, size_t index) {2780static IrInstruction *ir_instruction_breakpoint_get_dep(IrInstructionBreakpoint *instruction, size_t index) {
2731 return nullptr;2781 return nullptr;
2732}2782}
...@@ -3143,6 +3193,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -3143,6 +3193,10 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
3143 return ir_instruction_slice_get_dep((IrInstructionSlice *) instruction, index);3193 return ir_instruction_slice_get_dep((IrInstructionSlice *) instruction, index);
3144 case IrInstructionIdMemberCount:3194 case IrInstructionIdMemberCount:
3145 return ir_instruction_membercount_get_dep((IrInstructionMemberCount *) instruction, index);3195 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);
3146 case IrInstructionIdBreakpoint:3200 case IrInstructionIdBreakpoint:
3147 return ir_instruction_breakpoint_get_dep((IrInstructionBreakpoint *) instruction, index);3201 return ir_instruction_breakpoint_get_dep((IrInstructionBreakpoint *) instruction, index);
3148 case IrInstructionIdReturnAddress:3202 case IrInstructionIdReturnAddress:
...@@ -4379,6 +4433,36 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4379,6 +4433,36 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
43794433
4380 return ir_build_member_count(irb, scope, node, arg0_value);4434 return ir_build_member_count(irb, scope, node, arg0_value);
4381 }4435 }
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 }
4382 case BuiltinFnIdBreakpoint:4466 case BuiltinFnIdBreakpoint:
4383 return ir_build_breakpoint(irb, scope, node);4467 return ir_build_breakpoint(irb, scope, node);
4384 case BuiltinFnIdReturnAddress:4468 case BuiltinFnIdReturnAddress:
...@@ -14337,6 +14421,90 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns...@@ -14337,6 +14421,90 @@ static TypeTableEntry *ir_analyze_instruction_member_count(IrAnalyze *ira, IrIns
14337 return ira->codegen->builtin_types.entry_num_lit_int;14421 return ira->codegen->builtin_types.entry_num_lit_int;
14338}14422}
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
14340static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) {14508static TypeTableEntry *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) {
14341 ir_build_breakpoint_from(&ira->new_irb, &instruction->base);14509 ir_build_breakpoint_from(&ira->new_irb, &instruction->base);
14342 return ira->codegen->builtin_types.entry_void;14510 return ira->codegen->builtin_types.entry_void;
...@@ -15606,6 +15774,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -15606,6 +15774,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
15606 return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);15774 return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction);
15607 case IrInstructionIdMemberCount:15775 case IrInstructionIdMemberCount:
15608 return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction);15776 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);
15609 case IrInstructionIdBreakpoint:15781 case IrInstructionIdBreakpoint:
15610 return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction);15782 return ir_analyze_instruction_breakpoint(ira, (IrInstructionBreakpoint *)instruction);
15611 case IrInstructionIdReturnAddress:15783 case IrInstructionIdReturnAddress:
...@@ -15815,6 +15987,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -15815,6 +15987,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
15815 case IrInstructionIdBoolNot:15987 case IrInstructionIdBoolNot:
15816 case IrInstructionIdSlice:15988 case IrInstructionIdSlice:
15817 case IrInstructionIdMemberCount:15989 case IrInstructionIdMemberCount:
15990 case IrInstructionIdMemberType:
15991 case IrInstructionIdMemberName:
15818 case IrInstructionIdAlignOf:15992 case IrInstructionIdAlignOf:
15819 case IrInstructionIdReturnAddress:15993 case IrInstructionIdReturnAddress:
15820 case IrInstructionIdFrameAddress:15994 case IrInstructionIdFrameAddress:
src/ir_print.cpp+22
...@@ -658,6 +658,22 @@ static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instru...@@ -658,6 +658,22 @@ static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instru
658 fprintf(irp->f, ")");658 fprintf(irp->f, ")");
659}659}
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
661static void ir_print_breakpoint(IrPrint *irp, IrInstructionBreakpoint *instruction) {677static void ir_print_breakpoint(IrPrint *irp, IrInstructionBreakpoint *instruction) {
662 fprintf(irp->f, "@breakpoint()");678 fprintf(irp->f, "@breakpoint()");
663}679}
...@@ -1148,6 +1164,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1148,6 +1164,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1148 case IrInstructionIdMemberCount:1164 case IrInstructionIdMemberCount:
1149 ir_print_member_count(irp, (IrInstructionMemberCount *)instruction);1165 ir_print_member_count(irp, (IrInstructionMemberCount *)instruction);
1150 break;1166 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;
1151 case IrInstructionIdBreakpoint:1173 case IrInstructionIdBreakpoint:
1152 ir_print_breakpoint(irp, (IrInstructionBreakpoint *)instruction);1174 ir_print_breakpoint(irp, (IrInstructionBreakpoint *)instruction);
1153 break;1175 break;
test/cases/reflection.zig+43
...@@ -25,3 +25,46 @@ test "reflection: function return type, var args, and param types" {...@@ -25,3 +25,46 @@ test "reflection: function return type, var args, and param types" {
25fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }25fn dummy(a: bool, b: i32, c: f32) -> i32 { 1234 }
26fn dummy_varargs(args: ...) {}26fn 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) {...@@ -2289,4 +2289,50 @@ pub fn addCases(cases: &tests.CompileErrorContext) {
2289 \\fn add(a: i32, b: i32) -> i32 { return a + b; }2289 \\fn add(a: i32, b: i32) -> i32 { return a + b; }
2290 ,2290 ,
2291 ".tmp_source.zig:2:32: error: arg index 2 out of bounds; 'fn(i32, i32) -> i32' has 2 arguments");2291 ".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");
2292}2338}