authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-24 01:58:20-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-01-24 02:02:48-05:00
log4b3f18de3c5746b2ecfd6183351913de0909a83b
treee3d0d56fcd8c00d994a13c4d69d60f0ab28fe389
parent32d8686da80d282e8cd6d84a0e5c331d269a1f69

printf var args proof of concept

See #167 Need to troubleshoot when we send 2 slices to printf. It goes into an infinite loop. This commit introduces 4 builtin functions: * `@isInteger` * `@isFloat` * `@canImplictCast` * `@typeName`

9 files changed, 412 insertions(+), 38 deletions(-)

doc/langref.md+37-22
...@@ -370,10 +370,10 @@ TODO...@@ -370,10 +370,10 @@ TODO
370370
371## Built-in Functions371## Built-in Functions
372372
373Built-in functions are prefixed with `@`. Remember that the `inline` keyword on373Built-in functions are prefixed with `@`. Remember that the `comptime` keyword on
374a parameter means that the parameter must be known at compile time.374a parameter means that the parameter must be known at compile time.
375375
376### @alloca(inline T: type, count: usize) -> []T376### @alloca(comptime T: type, count: usize) -> []T
377377
378Allocates memory in the stack frame of the caller. This temporary space is378Allocates memory in the stack frame of the caller. This temporary space is
379automatically freed when the function that called alloca returns to its caller,379automatically freed when the function that called alloca returns to its caller,
...@@ -391,13 +391,13 @@ The allocated memory contents are undefined....@@ -391,13 +391,13 @@ The allocated memory contents are undefined.
391This function returns a compile-time constant, which is the type of the391This function returns a compile-time constant, which is the type of the
392expression passed as an argument. The expression is *not evaluated*.392expression passed as an argument. The expression is *not evaluated*.
393393
394### @sizeOf(inline T: type) -> (number literal)394### @sizeOf(comptime T: type) -> (number literal)
395395
396This function returns the number of bytes it takes to store T in memory.396This function returns the number of bytes it takes to store T in memory.
397397
398The result is a target-specific compile time constant.398The result is a target-specific compile time constant.
399399
400### @alignOf(inline T: type) -> (number literal)400### @alignOf(comptime T: type) -> (number literal)
401401
402This function returns the number of bytes that this type should be aligned to402This function returns the number of bytes that this type should be aligned to
403for the current target.403for the current target.
...@@ -414,10 +414,10 @@ false otherwise....@@ -414,10 +414,10 @@ false otherwise.
414414
415```415```
416Function Operation416Function Operation
417@addWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a + b417@addWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool *x = a + b
418@subWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a - b418@subWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool *x = a - b
419@mulWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a * b419@mulWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool *x = a * b
420@shlWithOverflow(inline T: type, a: T, b: T, result: &T) -> bool *x = a << b420@shlWithOverflow(comptime T: type, a: T, b: T, result: &T) -> bool *x = a << b
421```421```
422422
423### @memset(dest: &u8, c: u8, byte_count: usize)423### @memset(dest: &u8, c: u8, byte_count: usize)
...@@ -475,27 +475,27 @@ aggressive optimizations....@@ -475,27 +475,27 @@ aggressive optimizations.
475475
476This function is only valid within function scope.476This function is only valid within function scope.
477477
478### @maxValue(inline T: type) -> (number literal)478### @maxValue(comptime T: type) -> (number literal)
479479
480This function returns the maximum integer value of the integer type T.480This function returns the maximum integer value of the integer type T.
481481
482The result is a compile time constant. For some types such as `c_long`, the482The result is a compile time constant. For some types such as `c_long`, the
483result is marked as depending on a compile variable.483result is marked as depending on a compile variable.
484484
485### @minValue(inline T: type) -> (number literal)485### @minValue(comptime T: type) -> (number literal)
486486
487This function returns the minimum integer value of the integer type T.487This function returns the minimum integer value of the integer type T.
488488
489The result is a compile time constant. For some types such as `c_long`, the489The result is a compile time constant. For some types such as `c_long`, the
490result is marked as depending on a compile variable.490result is marked as depending on a compile variable.
491491
492### @memberCount(inline T: type) -> (number literal)492### @memberCount(comptime T: type) -> (number literal)
493493
494This function returns the number of enum values in an enum type.494This function returns the number of enum values in an enum type.
495495
496The result is a compile time constant.496The result is a compile time constant.
497497
498### @import(inline path: []u8) -> (namespace)498### @import(comptime path: []u8) -> (namespace)
499499
500This function finds a zig file corresponding to `path` and imports all the500This function finds a zig file corresponding to `path` and imports all the
501public top level declarations into the resulting namespace.501public top level declarations into the resulting namespace.
...@@ -516,25 +516,25 @@ appending to a temporary buffer which is then parsed as C code....@@ -516,25 +516,25 @@ appending to a temporary buffer which is then parsed as C code.
516516
517This function is only valid at top level scope.517This function is only valid at top level scope.
518518
519### @cInclude(inline path: []u8)519### @cInclude(comptime path: []u8)
520520
521This function can only occur inside `@c_import`.521This function can only occur inside `@c_import`.
522522
523This appends `#include <$path>\n` to the `c_import` temporary buffer.523This appends `#include <$path>\n` to the `c_import` temporary buffer.
524524
525### @cDefine(inline name: []u8, value)525### @cDefine(comptime name: []u8, value)
526526
527This function can only occur inside `@c_import`.527This function can only occur inside `@c_import`.
528528
529This appends `#define $name $value` to the `c_import` temporary buffer.529This appends `#define $name $value` to the `c_import` temporary buffer.
530530
531### @cUndef(inline name: []u8)531### @cUndef(comptime name: []u8)
532532
533This function can only occur inside `@c_import`.533This function can only occur inside `@c_import`.
534534
535This appends `#undef $name` to the `c_import` temporary buffer.535This appends `#undef $name` to the `c_import` temporary buffer.
536536
537### @compileVar(inline name: []u8) -> (varying type)537### @compileVar(comptime name: []u8) -> (varying type)
538538
539This function returns a compile-time variable. There are built in compile539This function returns a compile-time variable. There are built in compile
540variables:540variables:
...@@ -584,10 +584,14 @@ error OutOfMem;...@@ -584,10 +584,14 @@ error OutOfMem;
584584
585Then the string representation is "OutOfMem".585Then the string representation is "OutOfMem".
586586
587If there are no calls to `@err_name` in an entire application, then no error587If there are no calls to `@errorName` in an entire application, then no error
588name table will be generated.588name table will be generated.
589589
590### @embedFile(inline path: []u8) -> [X]u8590### @typeName(T: type) -> []u8
591
592This function returns the string representation of a type.
593
594### @embedFile(comptime path: []u8) -> [X]u8
591595
592This function returns a compile time constant fixed-size array with length596This function returns a compile time constant fixed-size array with length
593equal to the byte count of the file given by `path`. The contents of the array597equal to the byte count of the file given by `path`. The contents of the array
...@@ -610,7 +614,7 @@ The caller guarantees that this operation will have no remainder....@@ -610,7 +614,7 @@ The caller guarantees that this operation will have no remainder.
610In debug mode, a remainder causes a panic. In release mode, a remainder is614In debug mode, a remainder causes a panic. In release mode, a remainder is
611undefined behavior.615undefined behavior.
612616
613### @truncate(inline T: type, integer) -> T617### @truncate(comptime T: type, integer) -> T
614618
615This function truncates bits from an integer type, resulting in a smaller619This function truncates bits from an integer type, resulting in a smaller
616integer type.620integer type.
...@@ -631,14 +635,14 @@ const b: u8 = @truncate(u8, a);...@@ -631,14 +635,14 @@ const b: u8 = @truncate(u8, a);
631// b is now 0xcd635// b is now 0xcd
632```636```
633637
634### @compileError(inline msg: []u8)638### @compileError(comptime msg: []u8)
635639
636This function, when semantically analyzed, causes a compile error with the message `msg`.640This function, when semantically analyzed, causes a compile error with the message `msg`.
637641
638There are several ways that code avoids being semantically checked, such as using `if`642There are several ways that code avoids being semantically checked, such as using `if`
639or `switch` with compile time constants, and inline functions.643or `switch` with compile time constants, and comptime functions.
640644
641### @intType(inline is_signed: bool, inline bit_count: u8) -> type645### @intType(comptime is_signed: bool, comptime bit_count: u8) -> type
642646
643This function returns an integer type with the given signness and bit count.647This function returns an integer type with the given signness and bit count.
644648
...@@ -646,3 +650,14 @@ This function returns an integer type with the given signness and bit count....@@ -646,3 +650,14 @@ This function returns an integer type with the given signness and bit count.
646650
647Makes the target function a test function.651Makes the target function a test function.
648652
653### @isInteger(comptime T: type) -> bool
654
655Returns whether a given type is an integer.
656
657### @isFloat(comptime T: type) -> bool
658
659Returns whether a given type is a float.
660
661### @canImplicitCast(comptime T: type, value) -> bool
662
663Returns whether a value can be implicitly casted to a given type.
example/cat/main.zig-2
...@@ -2,8 +2,6 @@ const std = @import("std");...@@ -2,8 +2,6 @@ const std = @import("std");
2const io = std.io;2const io = std.io;
3const str = std.str;3const str = std.str;
44
5// TODO var args printing
6
7pub fn main(args: [][]u8) -> %void {5pub fn main(args: [][]u8) -> %void {
8 const exe = args[0];6 const exe = args[0];
9 var catted_anything = false;7 var catted_anything = false;
src/all_types.hpp+30
...@@ -978,6 +978,9 @@ struct TypeTableEntry {...@@ -978,6 +978,9 @@ struct TypeTableEntry {
978 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;978 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
979 TypeTableEntry *maybe_parent;979 TypeTableEntry *maybe_parent;
980 TypeTableEntry *error_parent;980 TypeTableEntry *error_parent;
981 // If we generate a constant name value for this type, we memoize it here.
982 // The type of this is array
983 ConstExprValue *cached_const_name_val;
981};984};
982985
983struct PackageTableEntry {986struct PackageTableEntry {
...@@ -1086,6 +1089,10 @@ enum BuiltinFnId {...@@ -1086,6 +1089,10 @@ enum BuiltinFnId {
1086 BuiltinFnIdSetFnVisible,1089 BuiltinFnIdSetFnVisible,
1087 BuiltinFnIdSetDebugSafety,1090 BuiltinFnIdSetDebugSafety,
1088 BuiltinFnIdAlloca,1091 BuiltinFnIdAlloca,
1092 BuiltinFnIdTypeName,
1093 BuiltinFnIdIsInteger,
1094 BuiltinFnIdIsFloat,
1095 BuiltinFnIdCanImplicitCast,
1089};1096};
10901097
1091struct BuiltinFnEntry {1098struct BuiltinFnEntry {
...@@ -1505,6 +1512,9 @@ enum IrInstructionId {...@@ -1505,6 +1512,9 @@ enum IrInstructionId {
1505 IrInstructionIdPtrToInt,1512 IrInstructionIdPtrToInt,
1506 IrInstructionIdIntToEnum,1513 IrInstructionIdIntToEnum,
1507 IrInstructionIdCheckSwitchProngs,1514 IrInstructionIdCheckSwitchProngs,
1515 IrInstructionIdTestType,
1516 IrInstructionIdTypeName,
1517 IrInstructionIdCanImplicitCast,
1508};1518};
15091519
1510struct IrInstruction {1520struct IrInstruction {
...@@ -2188,6 +2198,26 @@ struct IrInstructionCheckSwitchProngs {...@@ -2188,6 +2198,26 @@ struct IrInstructionCheckSwitchProngs {
2188 size_t range_count;2198 size_t range_count;
2189};2199};
21902200
2201struct IrInstructionTestType {
2202 IrInstruction base;
2203
2204 IrInstruction *type_value;
2205 TypeTableEntryId type_id;
2206};
2207
2208struct IrInstructionTypeName {
2209 IrInstruction base;
2210
2211 IrInstruction *type_value;
2212};
2213
2214struct IrInstructionCanImplicitCast {
2215 IrInstruction base;
2216
2217 IrInstruction *type_value;
2218 IrInstruction *target_value;
2219};
2220
2191enum LValPurpose {2221enum LValPurpose {
2192 LValPurposeNone,2222 LValPurposeNone,
2193 LValPurposeAssign,2223 LValPurposeAssign,
src/codegen.cpp+7
...@@ -2279,6 +2279,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2279,6 +2279,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2279 case IrInstructionIdTestComptime:2279 case IrInstructionIdTestComptime:
2280 case IrInstructionIdGeneratedCode:2280 case IrInstructionIdGeneratedCode:
2281 case IrInstructionIdCheckSwitchProngs:2281 case IrInstructionIdCheckSwitchProngs:
2282 case IrInstructionIdTestType:
2283 case IrInstructionIdTypeName:
2284 case IrInstructionIdCanImplicitCast:
2282 zig_unreachable();2285 zig_unreachable();
2283 case IrInstructionIdReturn:2286 case IrInstructionIdReturn:
2284 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);2287 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
...@@ -3652,6 +3655,10 @@ static void define_builtin_fns(CodeGen *g) {...@@ -3652,6 +3655,10 @@ static void define_builtin_fns(CodeGen *g) {
3652 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);3655 create_builtin_fn(g, BuiltinFnIdImport, "import", 1);
3653 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);3656 create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1);
3654 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);3657 create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1);
3658 create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1);
3659 create_builtin_fn(g, BuiltinFnIdIsInteger, "isInteger", 1);
3660 create_builtin_fn(g, BuiltinFnIdIsFloat, "isFloat", 1);
3661 create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2);
3655 create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);3662 create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1);
3656 create_builtin_fn(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);3663 create_builtin_fn(g, BuiltinFnIdCmpExchange, "cmpxchg", 5);
3657 create_builtin_fn(g, BuiltinFnIdFence, "fence", 1);3664 create_builtin_fn(g, BuiltinFnIdFence, "fence", 1);
src/ir.cpp+186-1
...@@ -495,6 +495,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckSwitchProng...@@ -495,6 +495,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckSwitchProng
495 return IrInstructionIdCheckSwitchProngs;495 return IrInstructionIdCheckSwitchProngs;
496}496}
497497
498static constexpr IrInstructionId ir_instruction_id(IrInstructionTestType *) {
499 return IrInstructionIdTestType;
500}
501
502static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeName *) {
503 return IrInstructionIdTypeName;
504}
505
506static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast *) {
507 return IrInstructionIdCanImplicitCast;
508}
509
498template<typename T>510template<typename T>
499static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {511static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
500 T *special_instruction = allocate<T>(1);512 T *special_instruction = allocate<T>(1);
...@@ -2001,6 +2013,45 @@ static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope,...@@ -2001,6 +2013,45 @@ static IrInstruction *ir_build_check_switch_prongs(IrBuilder *irb, Scope *scope,
2001 return &instruction->base;2013 return &instruction->base;
2002}2014}
20032015
2016static IrInstruction *ir_build_test_type(IrBuilder *irb, Scope *scope, AstNode *source_node,
2017 IrInstruction *type_value, TypeTableEntryId type_id)
2018{
2019 IrInstructionTestType *instruction = ir_build_instruction<IrInstructionTestType>(
2020 irb, scope, source_node);
2021 instruction->type_value = type_value;
2022 instruction->type_id = type_id;
2023
2024 ir_ref_instruction(type_value, irb->current_basic_block);
2025
2026 return &instruction->base;
2027}
2028
2029static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode *source_node,
2030 IrInstruction *type_value)
2031{
2032 IrInstructionTypeName *instruction = ir_build_instruction<IrInstructionTypeName>(
2033 irb, scope, source_node);
2034 instruction->type_value = type_value;
2035
2036 ir_ref_instruction(type_value, irb->current_basic_block);
2037
2038 return &instruction->base;
2039}
2040
2041static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node,
2042 IrInstruction *type_value, IrInstruction *target_value)
2043{
2044 IrInstructionCanImplicitCast *instruction = ir_build_instruction<IrInstructionCanImplicitCast>(
2045 irb, scope, source_node);
2046 instruction->type_value = type_value;
2047 instruction->target_value = target_value;
2048
2049 ir_ref_instruction(type_value, irb->current_basic_block);
2050 ir_ref_instruction(target_value, irb->current_basic_block);
2051
2052 return &instruction->base;
2053}
2054
2004static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {2055static IrInstruction *ir_instruction_br_get_dep(IrInstructionBr *instruction, size_t index) {
2005 return nullptr;2056 return nullptr;
2006}2057}
...@@ -2605,6 +2656,28 @@ static IrInstruction *ir_instruction_checkswitchprongs_get_dep(IrInstructionChec...@@ -2605,6 +2656,28 @@ static IrInstruction *ir_instruction_checkswitchprongs_get_dep(IrInstructionChec
2605 return nullptr;2656 return nullptr;
2606}2657}
26072658
2659static IrInstruction *ir_instruction_testtype_get_dep(IrInstructionTestType *instruction, size_t index) {
2660 switch (index) {
2661 case 0: return instruction->type_value;
2662 default: return nullptr;
2663 }
2664}
2665
2666static IrInstruction *ir_instruction_typename_get_dep(IrInstructionTypeName *instruction, size_t index) {
2667 switch (index) {
2668 case 0: return instruction->type_value;
2669 default: return nullptr;
2670 }
2671}
2672
2673static IrInstruction *ir_instruction_canimplicitcast_get_dep(IrInstructionCanImplicitCast *instruction, size_t index) {
2674 switch (index) {
2675 case 0: return instruction->type_value;
2676 case 1: return instruction->target_value;
2677 default: return nullptr;
2678 }
2679}
2680
2608static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {2681static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t index) {
2609 switch (instruction->id) {2682 switch (instruction->id) {
2610 case IrInstructionIdInvalid:2683 case IrInstructionIdInvalid:
...@@ -2777,6 +2850,12 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -2777,6 +2850,12 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
2777 return ir_instruction_inttoenum_get_dep((IrInstructionIntToEnum *) instruction, index);2850 return ir_instruction_inttoenum_get_dep((IrInstructionIntToEnum *) instruction, index);
2778 case IrInstructionIdCheckSwitchProngs:2851 case IrInstructionIdCheckSwitchProngs:
2779 return ir_instruction_checkswitchprongs_get_dep((IrInstructionCheckSwitchProngs *) instruction, index);2852 return ir_instruction_checkswitchprongs_get_dep((IrInstructionCheckSwitchProngs *) instruction, index);
2853 case IrInstructionIdTestType:
2854 return ir_instruction_testtype_get_dep((IrInstructionTestType *) instruction, index);
2855 case IrInstructionIdTypeName:
2856 return ir_instruction_typename_get_dep((IrInstructionTypeName *) instruction, index);
2857 case IrInstructionIdCanImplicitCast:
2858 return ir_instruction_canimplicitcast_get_dep((IrInstructionCanImplicitCast *) instruction, index);
2780 }2859 }
2781 zig_unreachable();2860 zig_unreachable();
2782}2861}
...@@ -3594,6 +3673,18 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *...@@ -3594,6 +3673,18 @@ static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *
3594 return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);3673 return ir_build_overflow_op(irb, scope, node, op, type_value, op1, op2, result_ptr, nullptr);
3595}3674}
35963675
3676static IrInstruction *ir_gen_test_type(IrBuilder *irb, Scope *scope, AstNode *node, TypeTableEntryId type_id) {
3677 assert(node->type == NodeTypeFnCallExpr);
3678
3679 AstNode *type_node = node->data.fn_call_expr.params.at(0);
3680
3681 IrInstruction *type_value = ir_gen_node(irb, type_node, scope);
3682 if (type_value == irb->codegen->invalid_instruction)
3683 return irb->codegen->invalid_instruction;
3684
3685 return ir_build_test_type(irb, scope, node, type_value, type_id);
3686}
3687
3597static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {3688static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node) {
3598 assert(node->type == NodeTypeFnCallExpr);3689 assert(node->type == NodeTypeFnCallExpr);
35993690
...@@ -3995,6 +4086,33 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -3995,6 +4086,33 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
3995 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul);4086 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul);
3996 case BuiltinFnIdShlWithOverflow:4087 case BuiltinFnIdShlWithOverflow:
3997 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl);4088 return ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl);
4089 case BuiltinFnIdTypeName:
4090 {
4091 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4092 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4093 if (arg0_value == irb->codegen->invalid_instruction)
4094 return arg0_value;
4095
4096 return ir_build_type_name(irb, scope, node, arg0_value);
4097 }
4098 case BuiltinFnIdIsInteger:
4099 return ir_gen_test_type(irb, scope, node, TypeTableEntryIdInt);
4100 case BuiltinFnIdIsFloat:
4101 return ir_gen_test_type(irb, scope, node, TypeTableEntryIdFloat);
4102 case BuiltinFnIdCanImplicitCast:
4103 {
4104 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4105 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4106 if (arg0_value == irb->codegen->invalid_instruction)
4107 return arg0_value;
4108
4109 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4110 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4111 if (arg1_value == irb->codegen->invalid_instruction)
4112 return arg1_value;
4113
4114 return ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value);
4115 }
3998 }4116 }
3999 zig_unreachable();4117 zig_unreachable();
4000}4118}
...@@ -8942,7 +9060,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi...@@ -8942,7 +9060,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi
8942 case TypeTableEntryIdEnumTag:9060 case TypeTableEntryIdEnumTag:
8943 case TypeTableEntryIdArgTuple:9061 case TypeTableEntryIdArgTuple:
8944 {9062 {
8945 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, false);9063 ConstExprValue *out_val = ir_build_const_from(ira, &typeof_instruction->base, true);
8946 // TODO depends_on_compile_var should be set based on whether the type of the expression9064 // TODO depends_on_compile_var should be set based on whether the type of the expression
8947 // depends_on_compile_var. but we currently don't have a thing to tell us if the type of9065 // depends_on_compile_var. but we currently don't have a thing to tell us if the type of
8948 // something depends on a compile var9066 // something depends on a compile var
...@@ -9622,6 +9740,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,...@@ -9622,6 +9740,8 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira,
9622 pointee_val = nullptr;9740 pointee_val = nullptr;
9623 }9741 }
9624 TypeTableEntry *canon_target_type = get_underlying_type(target_type);9742 TypeTableEntry *canon_target_type = get_underlying_type(target_type);
9743 ensure_complete_type(ira->codegen, target_type);
9744
9625 switch (canon_target_type->id) {9745 switch (canon_target_type->id) {
9626 case TypeTableEntryIdInvalid:9746 case TypeTableEntryIdInvalid:
9627 case TypeTableEntryIdVar:9747 case TypeTableEntryIdVar:
...@@ -10260,6 +10380,24 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc...@@ -10260,6 +10380,24 @@ static TypeTableEntry *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruc
10260 return str_type;10380 return str_type;
10261}10381}
1026210382
10383static TypeTableEntry *ir_analyze_instruction_type_name(IrAnalyze *ira, IrInstructionTypeName *instruction) {
10384 IrInstruction *type_value = instruction->type_value->other;
10385 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
10386 if (type_entry->id == TypeTableEntryIdInvalid)
10387 return ira->codegen->builtin_types.entry_invalid;
10388
10389 TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
10390 if (!type_entry->cached_const_name_val) {
10391 ConstExprValue *array_val = create_const_str_lit(ira->codegen, &type_entry->name);
10392 type_entry->cached_const_name_val = create_const_slice(ira->codegen,
10393 array_val, 0, buf_len(&type_entry->name), true);
10394 }
10395 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base,
10396 type_value->value.depends_on_compile_var);
10397 *out_val = *type_entry->cached_const_name_val;
10398 return str_type;
10399}
10400
10263static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {10401static TypeTableEntry *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstructionCImport *instruction) {
10264 AstNode *node = instruction->base.source_node;10402 AstNode *node = instruction->base.source_node;
10265 assert(node->type == NodeTypeFnCallExpr);10403 assert(node->type == NodeTypeFnCallExpr);
...@@ -11370,6 +11508,44 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira...@@ -11370,6 +11508,44 @@ static TypeTableEntry *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira
11370 return ira->codegen->builtin_types.entry_void;11508 return ira->codegen->builtin_types.entry_void;
11371}11509}
1137211510
11511static TypeTableEntry *ir_analyze_instruction_test_type(IrAnalyze *ira, IrInstructionTestType *instruction) {
11512 IrInstruction *type_value = instruction->type_value->other;
11513 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
11514 if (type_entry->id == TypeTableEntryIdInvalid)
11515 return ira->codegen->builtin_types.entry_invalid;
11516
11517 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, type_value->value.depends_on_compile_var);
11518 out_val->data.x_bool = (type_entry->id == instruction->type_id);
11519 return ira->codegen->builtin_types.entry_bool;
11520}
11521
11522static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira,
11523 IrInstructionCanImplicitCast *instruction)
11524{
11525 IrInstruction *type_value = instruction->type_value->other;
11526 TypeTableEntry *type_entry = ir_resolve_type(ira, type_value);
11527 if (type_entry->id == TypeTableEntryIdInvalid)
11528 return ira->codegen->builtin_types.entry_invalid;
11529
11530 IrInstruction *target_value = instruction->target_value->other;
11531 if (target_value->value.type->id == TypeTableEntryIdInvalid)
11532 return ira->codegen->builtin_types.entry_invalid;
11533
11534 ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, type_entry, target_value->value.type,
11535 target_value);
11536
11537 if (result == ImplicitCastMatchResultReportedError) {
11538 zig_panic("TODO refactor implicit cast tester to return bool without reporting errors");
11539 }
11540
11541 // TODO in order to known depends_on_compile_var we have to known if the type of the target
11542 // depends on a compile var
11543 bool depends_on_compile_var = true;
11544 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
11545 out_val->data.x_bool = (result == ImplicitCastMatchResultYes);
11546 return ira->codegen->builtin_types.entry_bool;
11547}
11548
11373static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {11549static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
11374 switch (instruction->id) {11550 switch (instruction->id) {
11375 case IrInstructionIdInvalid:11551 case IrInstructionIdInvalid:
...@@ -11471,6 +11647,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -11471,6 +11647,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
11471 return ir_analyze_instruction_compile_err(ira, (IrInstructionCompileErr *)instruction);11647 return ir_analyze_instruction_compile_err(ira, (IrInstructionCompileErr *)instruction);
11472 case IrInstructionIdErrName:11648 case IrInstructionIdErrName:
11473 return ir_analyze_instruction_err_name(ira, (IrInstructionErrName *)instruction);11649 return ir_analyze_instruction_err_name(ira, (IrInstructionErrName *)instruction);
11650 case IrInstructionIdTypeName:
11651 return ir_analyze_instruction_type_name(ira, (IrInstructionTypeName *)instruction);
11474 case IrInstructionIdCImport:11652 case IrInstructionIdCImport:
11475 return ir_analyze_instruction_c_import(ira, (IrInstructionCImport *)instruction);11653 return ir_analyze_instruction_c_import(ira, (IrInstructionCImport *)instruction);
11476 case IrInstructionIdCInclude:11654 case IrInstructionIdCInclude:
...@@ -11525,6 +11703,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -11525,6 +11703,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
11525 return ir_analyze_instruction_test_comptime(ira, (IrInstructionTestComptime *)instruction);11703 return ir_analyze_instruction_test_comptime(ira, (IrInstructionTestComptime *)instruction);
11526 case IrInstructionIdCheckSwitchProngs:11704 case IrInstructionIdCheckSwitchProngs:
11527 return ir_analyze_instruction_check_switch_prongs(ira, (IrInstructionCheckSwitchProngs *)instruction);11705 return ir_analyze_instruction_check_switch_prongs(ira, (IrInstructionCheckSwitchProngs *)instruction);
11706 case IrInstructionIdTestType:
11707 return ir_analyze_instruction_test_type(ira, (IrInstructionTestType *)instruction);
11708 case IrInstructionIdCanImplicitCast:
11709 return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction);
11528 case IrInstructionIdMaybeWrap:11710 case IrInstructionIdMaybeWrap:
11529 case IrInstructionIdErrWrapCode:11711 case IrInstructionIdErrWrapCode:
11530 case IrInstructionIdErrWrapPayload:11712 case IrInstructionIdErrWrapPayload:
...@@ -11691,6 +11873,9 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -11691,6 +11873,9 @@ bool ir_has_side_effects(IrInstruction *instruction) {
11691 case IrInstructionIdPtrToInt:11873 case IrInstructionIdPtrToInt:
11692 case IrInstructionIdIntToPtr:11874 case IrInstructionIdIntToPtr:
11693 case IrInstructionIdIntToEnum:11875 case IrInstructionIdIntToEnum:
11876 case IrInstructionIdTestType:
11877 case IrInstructionIdTypeName:
11878 case IrInstructionIdCanImplicitCast:
11694 return false;11879 return false;
11695 case IrInstructionIdAsm:11880 case IrInstructionIdAsm:
11696 {11881 {
src/ir_print.cpp+29
...@@ -807,6 +807,26 @@ static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchP...@@ -807,6 +807,26 @@ static void ir_print_check_switch_prongs(IrPrint *irp, IrInstructionCheckSwitchP
807 fprintf(irp->f, ")");807 fprintf(irp->f, ")");
808}808}
809809
810static void ir_print_test_type(IrPrint *irp, IrInstructionTestType *instruction) {
811 fprintf(irp->f, "@testType(");
812 ir_print_other_instruction(irp, instruction->type_value);
813 fprintf(irp->f, ")");
814}
815
816static void ir_print_type_name(IrPrint *irp, IrInstructionTypeName *instruction) {
817 fprintf(irp->f, "@typeName(");
818 ir_print_other_instruction(irp, instruction->type_value);
819 fprintf(irp->f, ")");
820}
821
822static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCast *instruction) {
823 fprintf(irp->f, "@canImplicitCast(");
824 ir_print_other_instruction(irp, instruction->type_value);
825 fprintf(irp->f, ",");
826 ir_print_other_instruction(irp, instruction->target_value);
827 fprintf(irp->f, ")");
828}
829
810static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {830static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
811 ir_print_prefix(irp, instruction);831 ir_print_prefix(irp, instruction);
812 switch (instruction->id) {832 switch (instruction->id) {
...@@ -1064,6 +1084,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1064,6 +1084,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1064 case IrInstructionIdCheckSwitchProngs:1084 case IrInstructionIdCheckSwitchProngs:
1065 ir_print_check_switch_prongs(irp, (IrInstructionCheckSwitchProngs *)instruction);1085 ir_print_check_switch_prongs(irp, (IrInstructionCheckSwitchProngs *)instruction);
1066 break;1086 break;
1087 case IrInstructionIdTestType:
1088 ir_print_test_type(irp, (IrInstructionTestType *)instruction);
1089 break;
1090 case IrInstructionIdTypeName:
1091 ir_print_type_name(irp, (IrInstructionTypeName *)instruction);
1092 break;
1093 case IrInstructionIdCanImplicitCast:
1094 ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction);
1095 break;
1067 }1096 }
1068 fprintf(irp->f, "\n");1097 fprintf(irp->f, "\n");
1069}1098}
std/debug.zig+1-4
...@@ -50,10 +50,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {...@@ -50,10 +50,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
50 const compile_unit = findCompileUnit(st, return_address) ?? return error.MissingDebugInfo;50 const compile_unit = findCompileUnit(st, return_address) ?? return error.MissingDebugInfo;
51 const name = %return compile_unit.die.getAttrString(st, DW.AT_name);51 const name = %return compile_unit.die.getAttrString(st, DW.AT_name);
5252
53 %return out_stream.printInt(usize, return_address);53 %return out_stream.printf("{} -> {}\n", return_address, name);
54 %return out_stream.printf(" -> ");
55 %return out_stream.printf(name);
56 %return out_stream.printf("\n");
57 maybe_fp = *(&const ?&const u8)(fp);54 maybe_fp = *(&const ?&const u8)(fp);
58 }55 }
59 },56 },
std/io.zig+73-9
...@@ -80,7 +80,7 @@ pub const OutStream = struct {...@@ -80,7 +80,7 @@ pub const OutStream = struct {
80 self.index += 1;80 self.index += 1;
81 }81 }
8282
83 pub fn write(self: &OutStream, bytes: []const u8) -> %usize {83 pub fn write(self: &OutStream, bytes: []const u8) -> %void {
84 var src_bytes_left = bytes.len;84 var src_bytes_left = bytes.len;
85 var src_index: usize = 0;85 var src_index: usize = 0;
86 const dest_space_left = self.buffer.len - self.index;86 const dest_space_left = self.buffer.len - self.index;
...@@ -94,25 +94,89 @@ pub const OutStream = struct {...@@ -94,25 +94,89 @@ pub const OutStream = struct {
94 }94 }
95 src_bytes_left -= copy_amt;95 src_bytes_left -= copy_amt;
96 }96 }
97 return bytes.len;
98 }97 }
9998
100 /// Prints a byte buffer, flushes the buffer, then returns the number of99 const State = enum { // TODO put inside printf function and make sure the name and debug info is correct
101 /// bytes printed. The "f" is for "flush".100 Start,
102 pub fn printf(self: &OutStream, str: []const u8) -> %usize {101 OpenBrace,
103 const byte_count = %return self.write(str);102 CloseBrace,
103 };
104
105 /// Calls print and then flushes the buffer.
106 pub fn printf(self: &OutStream, comptime format: []const u8, args: ...) -> %void {
107 comptime var start_index: usize = 0;
108 comptime var state = State.Start;
109 comptime var next_arg: usize = 0;
110 inline for (format) |c, i| {
111 switch (state) {
112 State.Start => switch (c) {
113 '{' => {
114 if (start_index < i) %return self.write(format[start_index...i]);
115 state = State.OpenBrace;
116 },
117 '}' => {
118 if (start_index < i) %return self.write(format[start_index...i]);
119 state = State.CloseBrace;
120 },
121 else => {},
122 },
123 State.OpenBrace => switch (c) {
124 '{' => {
125 state = State.Start;
126 start_index = i;
127 },
128 '}' => {
129 %return self.printValue(args[next_arg]);
130 next_arg += 1;
131 state = State.Start;
132 start_index = i + 1;
133 },
134 else => @compileError("Unknown format character: " ++ c),
135 },
136 State.CloseBrace => switch (c) {
137 '}' => {
138 state = State.Start;
139 start_index = i;
140 },
141 else => @compileError("Single '}' encountered in format string"),
142 },
143 }
144 }
145 comptime {
146 if (args.len != next_arg) {
147 @compileError("Unused arguments");
148 }
149 if (state != State.Start) {
150 @compileError("Incomplete format string: " ++ format);
151 }
152 }
153 inline if (start_index < format.len) {
154 %return self.write(format[start_index...format.len]);
155 }
104 %return self.flush();156 %return self.flush();
105 return byte_count;
106 }157 }
107158
108 pub fn printInt(self: &OutStream, comptime T: type, x: T) -> %usize {159 pub fn printValue(self: &OutStream, value: var) -> %void {
160 const T = @typeOf(value);
161 if (@isInteger(T)) {
162 return self.printInt(T, value);
163 } else if (@isFloat(T)) {
164 return self.printFloat(T, value);
165 } else if (@canImplicitCast([]const u8, value)) {
166 const casted_value = ([]const u8)(value);
167 return self.write(casted_value);
168 } else {
169 @compileError("Unable to print type '" ++ @typeName(T) ++ "'");
170 }
171 }
172
173 pub fn printInt(self: &OutStream, comptime T: type, x: T) -> %void {
109 // TODO replace max_u64_base10_digits with math.log10(math.pow(2, @sizeOf(T)))174 // TODO replace max_u64_base10_digits with math.log10(math.pow(2, @sizeOf(T)))
110 if (self.index + max_u64_base10_digits >= self.buffer.len) {175 if (self.index + max_u64_base10_digits >= self.buffer.len) {
111 %return self.flush();176 %return self.flush();
112 }177 }
113 const amt_printed = bufPrintInt(T, self.buffer[self.index...], x);178 const amt_printed = bufPrintInt(T, self.buffer[self.index...], x);
114 self.index += amt_printed;179 self.index += amt_printed;
115 return amt_printed;
116 }180 }
117181
118 pub fn flush(self: &OutStream) -> %void {182 pub fn flush(self: &OutStream) -> %void {
test/cases/misc.zig+49
...@@ -517,3 +517,52 @@ fn testArray2DConstDoublePtr(ptr: &const f32) {...@@ -517,3 +517,52 @@ fn testArray2DConstDoublePtr(ptr: &const f32) {
517 assert(ptr[0] == 1.0);517 assert(ptr[0] == 1.0);
518 assert(ptr[1] == 2.0);518 assert(ptr[1] == 2.0);
519}519}
520
521fn isInteger() {
522 @setFnTest(this);
523
524 comptime {
525 assert(@isInteger(i8));
526 assert(@isInteger(u8));
527 assert(@isInteger(i64));
528 assert(@isInteger(u64));
529 assert(!@isInteger(f32));
530 assert(!@isInteger(f64));
531 assert(!@isInteger(bool));
532 assert(!@isInteger(&i32));
533 }
534}
535
536fn isFloat() {
537 @setFnTest(this);
538
539 comptime {
540 assert(!@isFloat(i8));
541 assert(!@isFloat(u8));
542 assert(!@isFloat(i64));
543 assert(!@isFloat(u64));
544 assert(@isFloat(f32));
545 assert(@isFloat(f64));
546 assert(!@isFloat(bool));
547 assert(!@isFloat(&f32));
548 }
549}
550
551fn canImplicitCast() {
552 @setFnTest(this);
553
554 comptime {
555 assert(@canImplicitCast(i64, i32(3)));
556 assert(!@canImplicitCast(i32, f32(1.234)));
557 assert(@canImplicitCast([]const u8, "aoeu"));
558 }
559}
560
561fn typeName() {
562 @setFnTest(this);
563
564 comptime {
565 assert(str.eql(@typeName(i64), "i64"));
566 assert(str.eql(@typeName(&usize), "&usize"));
567 }
568}