From d3693dca73dfc726aed32908691437abe614e5cf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 6 Jun 2018 00:39:39 -0400 Subject: Pointer Reform: update @typeInfo * add assertion for trying to do @typeInfo on global error set * remove TypeInfo.Slice * add TypeInfo.Pointer.Size with possible values - One - Many - Slice See #770 --- src/codegen.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index a977c34daf..7f95f335d1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6481,7 +6481,6 @@ static void define_builtin_compile_vars(CodeGen *g) { const TypeTableEntryId id = type_id_at_index(i); buf_appendf(contents, " %s,\n", type_id_name(id)); } - buf_appendf(contents, " Slice,\n"); buf_appendf(contents, "};\n\n"); } { @@ -6494,7 +6493,6 @@ static void define_builtin_compile_vars(CodeGen *g) { " Int: Int,\n" " Float: Float,\n" " Pointer: Pointer,\n" - " Slice: Slice,\n" " Array: Array,\n" " Struct: Struct,\n" " ComptimeFloat: void,\n" @@ -6524,13 +6522,18 @@ static void define_builtin_compile_vars(CodeGen *g) { " };\n" "\n" " pub const Pointer = struct {\n" + " size: Size,\n" " is_const: bool,\n" " is_volatile: bool,\n" " alignment: u32,\n" " child: type,\n" - " };\n" "\n" - " pub const Slice = Pointer;\n" + " pub const Size = enum {\n" + " One,\n" + " Many,\n" + " Slice,\n" + " };\n" + " };\n" "\n" " pub const Array = struct {\n" " len: usize,\n" -- cgit v1.2.3 From 688ff2830d82ea36a9f022ecb7cf4c2bf2e4c586 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Jun 2018 19:10:45 -0400 Subject: langref: automatic update of builtin.zig now the docs can't get out of date for this See #367 --- doc/docgen.zig | 18 +++ doc/langref.html.in | 423 +--------------------------------------------------- src/codegen.cpp | 21 ++- src/codegen.hpp | 2 + src/main.cpp | 15 ++ 5 files changed, 51 insertions(+), 428 deletions(-) (limited to 'src/codegen.cpp') diff --git a/doc/docgen.zig b/doc/docgen.zig index fed4bb8eba..ed0e1be273 100644 --- a/doc/docgen.zig +++ b/doc/docgen.zig @@ -300,6 +300,7 @@ const Link = struct { const Node = union(enum) { Content: []const u8, Nav, + Builtin, HeaderOpen: HeaderOpen, SeeAlso: []const SeeAlsoItem, Code: Code, @@ -356,6 +357,9 @@ fn genToc(allocator: *mem.Allocator, tokenizer: *Tokenizer) !Toc { _ = try eatToken(tokenizer, Token.Id.BracketClose); try nodes.append(Node.Nav); + } else if (mem.eql(u8, tag_name, "builtin")) { + _ = try eatToken(tokenizer, Token.Id.BracketClose); + try nodes.append(Node.Builtin); } else if (mem.eql(u8, tag_name, "header_open")) { _ = try eatToken(tokenizer, Token.Id.Separator); const content_token = try eatToken(tokenizer, Token.Id.TagContent); @@ -690,6 +694,9 @@ fn termColor(allocator: *mem.Allocator, input: []const u8) ![]u8 { fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var, zig_exe: []const u8) !void { var code_progress_index: usize = 0; + + const builtin_code = try escapeHtml(allocator, try getBuiltinCode(allocator, zig_exe)); + for (toc.nodes) |node| { switch (node) { Node.Content => |data| { @@ -704,6 +711,9 @@ fn genHtml(allocator: *mem.Allocator, tokenizer: *Tokenizer, toc: *Toc, out: var Node.Nav => { try out.write(toc.toc); }, + Node.Builtin => { + try out.print("
{}
", builtin_code); + }, Node.HeaderOpen => |info| { try out.print("{}\n", info.n, info.url, info.name, info.n); }, @@ -1060,3 +1070,11 @@ fn exec(allocator: *mem.Allocator, args: []const []const u8) !os.ChildProcess.Ex } return result; } + +fn getBuiltinCode(allocator: *mem.Allocator, zig_exe: []const u8) ![]const u8 { + const result = try exec(allocator, []const []const u8{ + zig_exe, + "builtin", + }); + return result.stdout; +} diff --git a/doc/langref.html.in b/doc/langref.html.in index 4359cadb58..adb5470d98 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5474,425 +5474,7 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';

Example of what is imported with @import("builtin"):

- {#code_begin|syntax#} -pub const StackTrace = struct { - index: usize, - instruction_addresses: []usize, -}; - -pub const Os = enum { - freestanding, - ananas, - cloudabi, - dragonfly, - freebsd, - fuchsia, - ios, - kfreebsd, - linux, - lv2, - macosx, - netbsd, - openbsd, - solaris, - windows, - haiku, - minix, - rtems, - nacl, - cnk, - aix, - cuda, - nvcl, - amdhsa, - ps4, - elfiamcu, - tvos, - watchos, - mesa3d, - contiki, - amdpal, - zen, -}; - -pub const Arch = enum { - armv8_3a, - armv8_2a, - armv8_1a, - armv8, - armv8r, - armv8m_baseline, - armv8m_mainline, - armv7, - armv7em, - armv7m, - armv7s, - armv7k, - armv7ve, - armv6, - armv6m, - armv6k, - armv6t2, - armv5, - armv5te, - armv4t, - armebv8_3a, - armebv8_2a, - armebv8_1a, - armebv8, - armebv8r, - armebv8m_baseline, - armebv8m_mainline, - armebv7, - armebv7em, - armebv7m, - armebv7s, - armebv7k, - armebv7ve, - armebv6, - armebv6m, - armebv6k, - armebv6t2, - armebv5, - armebv5te, - armebv4t, - aarch64, - aarch64_be, - arc, - avr, - bpfel, - bpfeb, - hexagon, - mips, - mipsel, - mips64, - mips64el, - msp430, - nios2, - powerpc, - powerpc64, - powerpc64le, - r600, - amdgcn, - riscv32, - riscv64, - sparc, - sparcv9, - sparcel, - s390x, - tce, - tcele, - thumb, - thumbeb, - i386, - x86_64, - xcore, - nvptx, - nvptx64, - le32, - le64, - amdil, - amdil64, - hsail, - hsail64, - spir, - spir64, - kalimbav3, - kalimbav4, - kalimbav5, - shave, - lanai, - wasm32, - wasm64, - renderscript32, - renderscript64, -}; - -pub const Environ = enum { - unknown, - gnu, - gnuabin32, - gnuabi64, - gnueabi, - gnueabihf, - gnux32, - code16, - eabi, - eabihf, - android, - musl, - musleabi, - musleabihf, - msvc, - itanium, - cygnus, - amdopencl, - coreclr, - opencl, - simulator, -}; - -pub const ObjectFormat = enum { - unknown, - coff, - elf, - macho, - wasm, -}; - -pub const GlobalLinkage = enum { - Internal, - Strong, - Weak, - LinkOnce, -}; - -pub const AtomicOrder = enum { - Unordered, - Monotonic, - Acquire, - Release, - AcqRel, - SeqCst, -}; - -pub const AtomicRmwOp = enum { - Xchg, - Add, - Sub, - And, - Nand, - Or, - Xor, - Max, - Min, -}; - -pub const Mode = enum { - Debug, - ReleaseSafe, - ReleaseFast, - ReleaseSmall, -}; - -pub const TypeId = enum { - Type, - Void, - Bool, - NoReturn, - Int, - Float, - Pointer, - Array, - Struct, - ComptimeFloat, - ComptimeInt, - Undefined, - Null, - Nullable, - ErrorUnion, - ErrorSet, - Enum, - Union, - Fn, - Namespace, - Block, - BoundFn, - ArgTuple, - Opaque, - Promise, -}; - -pub const TypeInfo = union(TypeId) { - Type: void, - Void: void, - Bool: void, - NoReturn: void, - Int: Int, - Float: Float, - Pointer: Pointer, - Array: Array, - Struct: Struct, - ComptimeFloat: void, - ComptimeInt: void, - Undefined: void, - Null: void, - Nullable: Nullable, - ErrorUnion: ErrorUnion, - ErrorSet: ErrorSet, - Enum: Enum, - Union: Union, - Fn: Fn, - Namespace: void, - Block: void, - BoundFn: Fn, - ArgTuple: void, - Opaque: void, - Promise: Promise, - - - pub const Int = struct { - is_signed: bool, - bits: u8, - }; - - pub const Float = struct { - bits: u8, - }; - - pub const Pointer = struct { - is_const: bool, - is_volatile: bool, - alignment: u32, - child: type, - }; - - pub const Array = struct { - len: usize, - child: type, - }; - - pub const ContainerLayout = enum { - Auto, - Extern, - Packed, - }; - - pub const StructField = struct { - name: []const u8, - offset: ?usize, - field_type: type, - }; - - pub const Struct = struct { - layout: ContainerLayout, - fields: []StructField, - defs: []Definition, - }; - - pub const Nullable = struct { - child: type, - }; - - pub const ErrorUnion = struct { - error_set: type, - payload: type, - }; - - pub const Error = struct { - name: []const u8, - value: usize, - }; - - pub const ErrorSet = struct { - errors: []Error, - }; - - pub const EnumField = struct { - name: []const u8, - value: usize, - }; - - pub const Enum = struct { - layout: ContainerLayout, - tag_type: type, - fields: []EnumField, - defs: []Definition, - }; - - pub const UnionField = struct { - name: []const u8, - enum_field: ?EnumField, - field_type: type, - }; - - pub const Union = struct { - layout: ContainerLayout, - tag_type: type, - fields: []UnionField, - defs: []Definition, - }; - - pub const CallingConvention = enum { - Unspecified, - C, - Cold, - Naked, - Stdcall, - Async, - }; - - pub const FnArg = struct { - is_generic: bool, - is_noalias: bool, - arg_type: type, - }; - - pub const Fn = struct { - calling_convention: CallingConvention, - is_generic: bool, - is_var_args: bool, - return_type: type, - async_allocator_type: type, - args: []FnArg, - }; - - pub const Promise = struct { - child: type, - }; - - pub const Definition = struct { - name: []const u8, - is_pub: bool, - data: Data, - - pub const Data = union(enum) { - Type: type, - Var: type, - Fn: FnDef, - - pub const FnDef = struct { - fn_type: type, - inline_type: Inline, - calling_convention: CallingConvention, - is_var_args: bool, - is_extern: bool, - is_export: bool, - lib_name: ?[]const u8, - return_type: type, - arg_names: [][] const u8, - - pub const Inline = enum { - Auto, - Always, - Never, - }; - }; - }; - }; -}; - -pub const FloatMode = enum { - Optimized, - Strict, -}; - -pub const Endian = enum { - Big, - Little, -}; - -pub const endian = Endian.Little; -pub const is_test = true; -pub const os = Os.linux; -pub const arch = Arch.x86_64; -pub const environ = Environ.gnu; -pub const object_format = ObjectFormat.elf; -pub const mode = Mode.Debug; -pub const link_libc = false; -pub const have_error_return_tracing = true; -pub const __zig_test_fn_slice = {}; // overwritten later - {#code_end#} + {#builtin#} {#see_also|Build Mode#} {#header_close#} {#header_open|Root Source File#} @@ -6053,8 +5635,7 @@ pub fn build(b: *Builder) void { b.default_step.dependOn(&exe.step); } {#code_end#} - {#header_close#} - {#header_open|Terminal#} +

terminal

$ zig build
 $ ./test
 all your base are belong to us
diff --git a/src/codegen.cpp b/src/codegen.cpp index 7f95f335d1..fb59ca7569 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6335,13 +6335,7 @@ static const char *build_mode_to_str(BuildMode build_mode) { zig_unreachable(); } -static void define_builtin_compile_vars(CodeGen *g) { - if (g->std_package == nullptr) - return; - - const char *builtin_zig_basename = "builtin.zig"; - Buf *builtin_zig_path = buf_alloc(); - os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); +Buf *codegen_generate_builtin_source(CodeGen *g) { Buf *contents = buf_alloc(); // Modifications to this struct must be coordinated with code that does anything with @@ -6707,6 +6701,19 @@ static void define_builtin_compile_vars(CodeGen *g) { buf_appendf(contents, "pub const __zig_test_fn_slice = {}; // overwritten later\n"); + + return contents; +} + +static void define_builtin_compile_vars(CodeGen *g) { + if (g->std_package == nullptr) + return; + + const char *builtin_zig_basename = "builtin.zig"; + Buf *builtin_zig_path = buf_alloc(); + os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path); + + Buf *contents = codegen_generate_builtin_source(g); ensure_cache_dir(g); os_write_file(builtin_zig_path, contents); diff --git a/src/codegen.hpp b/src/codegen.hpp index a7a4b748c4..b5f3374ec4 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -59,5 +59,7 @@ void codegen_add_object(CodeGen *g, Buf *object_path); void codegen_translate_c(CodeGen *g, Buf *path); +Buf *codegen_generate_builtin_source(CodeGen *g); + #endif diff --git a/src/main.cpp b/src/main.cpp index 9c36f9b091..c63a143bff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ static int usage(const char *arg0) { " build-exe [source] create executable from source or object files\n" " build-lib [source] create library from source or object files\n" " build-obj [source] create object from source or assembly\n" + " builtin show the source code of that @import(\"builtin\")\n" " run [source] create executable and run immediately\n" " translate-c [source] convert c code to zig code\n" " targets list available compilation targets\n" @@ -214,6 +215,7 @@ static Buf *resolve_zig_lib_dir(void) { enum Cmd { CmdInvalid, CmdBuild, + CmdBuiltin, CmdRun, CmdTest, CmdVersion, @@ -664,6 +666,8 @@ int main(int argc, char **argv) { out_type = OutTypeExe; } else if (strcmp(arg, "targets") == 0) { cmd = CmdTargets; + } else if (strcmp(arg, "builtin") == 0) { + cmd = CmdBuiltin; } else { fprintf(stderr, "Unrecognized command: %s\n", arg); return usage(arg0); @@ -681,6 +685,7 @@ int main(int argc, char **argv) { return usage(arg0); } break; + case CmdBuiltin: case CmdVersion: case CmdZen: case CmdTargets: @@ -727,6 +732,16 @@ int main(int argc, char **argv) { } switch (cmd) { + case CmdBuiltin: { + Buf *zig_lib_dir_buf = resolve_zig_lib_dir(); + CodeGen *g = codegen_create(nullptr, target, out_type, build_mode, zig_lib_dir_buf); + Buf *builtin_source = codegen_generate_builtin_source(g); + if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { + fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout))); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; + } case CmdRun: case CmdBuild: case CmdTranslateC: -- cgit v1.2.3 From b65203f5736199bdc8d98d27728be5e92a17d565 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Jun 2018 19:50:25 -0400 Subject: remove @canImplicitCast builtin nobody will miss it --- doc/langref.html.in | 11 +--------- src/all_types.hpp | 9 -------- src/codegen.cpp | 2 -- src/ir.cpp | 60 ----------------------------------------------------- src/ir_print.cpp | 11 ---------- test/cases/misc.zig | 8 ------- 6 files changed, 1 insertion(+), 100 deletions(-) (limited to 'src/codegen.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index adb5470d98..6a1f1c3102 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -3845,9 +3845,6 @@ pub fn printValue(self: *OutStream, value: var) !void { return self.printInt(T, value); } else if (@isFloat(T)) { return self.printFloat(T, value); - } else if (@canImplicitCast([]const u8, value)) { - const casted_value = ([]const u8)(value); - return self.write(casted_value); } else { @compileError("Unable to print type '" ++ @typeName(T) ++ "'"); } @@ -4102,12 +4099,6 @@ comptime {

{#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#} {#header_close#} - {#header_open|@canImplicitCast#} -
@canImplicitCast(comptime T: type, value) bool
-

- Returns whether a value can be implicitly casted to a given type. -

- {#header_close#} {#header_open|@clz#}
@clz(x: T) U

@@ -6136,7 +6127,7 @@ hljs.registerLanguage("zig", function(t) { a = t.IR + "\\s*\\(", c = { keyword: "const align var extern stdcallcc nakedcc volatile export pub noalias inline struct packed enum union break return try catch test continue unreachable comptime and or asm defer errdefer if else switch while for fn use bool f32 f64 void type noreturn error i8 u8 i16 u16 i32 u32 i64 u64 isize usize i8w u8w i16w i32w u32w i64w u64w isizew usizew c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong", - built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic canImplicitCast ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall", + built_in: "atomicLoad breakpoint returnAddress frameAddress fieldParentPtr setFloatMode IntType OpaqueType compileError compileLog setCold setRuntimeSafety setEvalBranchQuota offsetOf memcpy inlineCall setGlobalLinkage setGlobalSection divTrunc divFloor enumTagName intToPtr ptrToInt panic ptrCast bitCast rem mod memset sizeOf alignOf alignCast maxValue minValue memberCount memberName memberType typeOf addWithOverflow subWithOverflow mulWithOverflow shlWithOverflow shlExact shrExact cInclude cDefine cUndef ctz clz import cImport errorName embedFile cmpxchgStrong cmpxchgWeak fence divExact truncate atomicRmw sqrt field typeInfo typeName newStackCall", literal: "true false null undefined" }, n = [e, t.CLCM, t.CBCM, s, r]; diff --git a/src/all_types.hpp b/src/all_types.hpp index b193fe8ae8..9d41b86fa0 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1354,7 +1354,6 @@ enum BuiltinFnId { BuiltinFnIdSetRuntimeSafety, BuiltinFnIdSetFloatMode, BuiltinFnIdTypeName, - BuiltinFnIdCanImplicitCast, BuiltinFnIdPanic, BuiltinFnIdPtrCast, BuiltinFnIdBitCast, @@ -2065,7 +2064,6 @@ enum IrInstructionId { IrInstructionIdCheckSwitchProngs, IrInstructionIdCheckStatementIsVoid, IrInstructionIdTypeName, - IrInstructionIdCanImplicitCast, IrInstructionIdDeclRef, IrInstructionIdPanic, IrInstructionIdTagName, @@ -2858,13 +2856,6 @@ struct IrInstructionTypeName { IrInstruction *type_value; }; -struct IrInstructionCanImplicitCast { - IrInstruction base; - - IrInstruction *type_value; - IrInstruction *target_value; -}; - struct IrInstructionDeclRef { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index fb59ca7569..d156a8a178 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4625,7 +4625,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdCheckSwitchProngs: case IrInstructionIdCheckStatementIsVoid: case IrInstructionIdTypeName: - case IrInstructionIdCanImplicitCast: case IrInstructionIdDeclRef: case IrInstructionIdSwitchVar: case IrInstructionIdOffsetOf: @@ -6277,7 +6276,6 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdCImport, "cImport", 1); create_builtin_fn(g, BuiltinFnIdErrName, "errorName", 1); create_builtin_fn(g, BuiltinFnIdTypeName, "typeName", 1); - create_builtin_fn(g, BuiltinFnIdCanImplicitCast, "canImplicitCast", 2); create_builtin_fn(g, BuiltinFnIdEmbedFile, "embedFile", 1); create_builtin_fn(g, BuiltinFnIdCmpxchgWeak, "cmpxchgWeak", 6); create_builtin_fn(g, BuiltinFnIdCmpxchgStrong, "cmpxchgStrong", 6); diff --git a/src/ir.cpp b/src/ir.cpp index 304127b099..3c9adab796 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -585,10 +585,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeName *) { return IrInstructionIdTypeName; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionCanImplicitCast *) { - return IrInstructionIdCanImplicitCast; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionDeclRef *) { return IrInstructionIdDeclRef; } @@ -2348,20 +2344,6 @@ static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode * return &instruction->base; } -static IrInstruction *ir_build_can_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *type_value, IrInstruction *target_value) -{ - IrInstructionCanImplicitCast *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->type_value = type_value; - instruction->target_value = target_value; - - ir_ref_instruction(type_value, irb->current_basic_block); - ir_ref_instruction(target_value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { @@ -4132,21 +4114,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value); return ir_lval_wrap(irb, scope, type_name, lval); } - case BuiltinFnIdCanImplicitCast: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_instruction) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_instruction) - return arg1_value; - - IrInstruction *can_implicit_cast = ir_build_can_implicit_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, can_implicit_cast, lval); - } case BuiltinFnIdPanic: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -18405,30 +18372,6 @@ static TypeTableEntry *ir_analyze_instruction_check_statement_is_void(IrAnalyze return ira->codegen->builtin_types.entry_void; } -static TypeTableEntry *ir_analyze_instruction_can_implicit_cast(IrAnalyze *ira, - IrInstructionCanImplicitCast *instruction) -{ - IrInstruction *type_value = instruction->type_value->other; - TypeTableEntry *type_entry = ir_resolve_type(ira, type_value); - if (type_is_invalid(type_entry)) - return ira->codegen->builtin_types.entry_invalid; - - IrInstruction *target_value = instruction->target_value->other; - if (type_is_invalid(target_value->value.type)) - return ira->codegen->builtin_types.entry_invalid; - - ImplicitCastMatchResult result = ir_types_match_with_implicit_cast(ira, type_entry, target_value->value.type, - target_value); - - if (result == ImplicitCastMatchResultReportedError) { - zig_panic("TODO refactor implicit cast tester to return bool without reporting errors"); - } - - ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_bool = (result == ImplicitCastMatchResultYes); - return ira->codegen->builtin_types.entry_bool; -} - static TypeTableEntry *ir_analyze_instruction_panic(IrAnalyze *ira, IrInstructionPanic *instruction) { IrInstruction *msg = instruction->msg->other; if (type_is_invalid(msg->value.type)) @@ -19762,8 +19705,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_check_switch_prongs(ira, (IrInstructionCheckSwitchProngs *)instruction); case IrInstructionIdCheckStatementIsVoid: return ir_analyze_instruction_check_statement_is_void(ira, (IrInstructionCheckStatementIsVoid *)instruction); - case IrInstructionIdCanImplicitCast: - return ir_analyze_instruction_can_implicit_cast(ira, (IrInstructionCanImplicitCast *)instruction); case IrInstructionIdDeclRef: return ir_analyze_instruction_decl_ref(ira, (IrInstructionDeclRef *)instruction); case IrInstructionIdPanic: @@ -20043,7 +19984,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdIntToEnum: case IrInstructionIdIntToErr: case IrInstructionIdErrToInt: - case IrInstructionIdCanImplicitCast: case IrInstructionIdDeclRef: case IrInstructionIdErrName: case IrInstructionIdTypeName: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3c177a8bbf..776ef64566 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -913,14 +913,6 @@ static void ir_print_tag_name(IrPrint *irp, IrInstructionTagName *instruction) { ir_print_other_instruction(irp, instruction->target); } -static void ir_print_can_implicit_cast(IrPrint *irp, IrInstructionCanImplicitCast *instruction) { - fprintf(irp->f, "@canImplicitCast("); - ir_print_other_instruction(irp, instruction->type_value); - fprintf(irp->f, ","); - ir_print_other_instruction(irp, instruction->target_value); - fprintf(irp->f, ")"); -} - static void ir_print_ptr_type(IrPrint *irp, IrInstructionPtrType *instruction) { fprintf(irp->f, "&"); if (instruction->align_value != nullptr) { @@ -1524,9 +1516,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTagName: ir_print_tag_name(irp, (IrInstructionTagName *)instruction); break; - case IrInstructionIdCanImplicitCast: - ir_print_can_implicit_cast(irp, (IrInstructionCanImplicitCast *)instruction); - break; case IrInstructionIdPtrType: ir_print_ptr_type(irp, (IrInstructionPtrType *)instruction); break; diff --git a/test/cases/misc.zig b/test/cases/misc.zig index 9450cf5e6e..369d8e5cf3 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -523,14 +523,6 @@ test "@typeId" { } } -test "@canImplicitCast" { - comptime { - assert(@canImplicitCast(i64, i32(3))); - assert(!@canImplicitCast(i32, f32(1.234))); - assert(@canImplicitCast([]const u8, "aoeu")); - } -} - test "@typeName" { const Struct = struct {}; const Union = union { -- cgit v1.2.3 From f0b6dac1f2d37ea9eff0116bec34e9b2be9f3ce7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 7 Jun 2018 22:19:00 -0400 Subject: add implicit casts from `*[N]T` * to `[]T` * to `[*]T` See #770 --- src/all_types.hpp | 1 + src/codegen.cpp | 26 ++++++++++- src/ir.cpp | 122 ++++++++++++++++++++++++++++++++++++++++++++++++++++ test/cases/cast.zig | 16 +++++++ 4 files changed, 163 insertions(+), 2 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 9d41b86fa0..c671682363 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -583,6 +583,7 @@ enum CastOp { CastOpNumLitToConcrete, CastOpErrSet, CastOpBitCast, + CastOpPtrOfArrayToSlice, }; struct AstNodeFnCallExpr { diff --git a/src/codegen.cpp b/src/codegen.cpp index d156a8a178..fab2ad659e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2530,7 +2530,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, assert(wanted_type->data.structure.is_slice); assert(actual_type->id == TypeTableEntryIdArray); - TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[0].type_entry; + TypeTableEntry *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; TypeTableEntry *wanted_child_type = wanted_pointer_type->data.pointer.child_type; @@ -2576,6 +2576,29 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, return expr_val; case CastOpBitCast: return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, ""); + case CastOpPtrOfArrayToSlice: { + assert(cast_instruction->tmp_ptr); + assert(actual_type->id == TypeTableEntryIdPointer); + TypeTableEntry *array_type = actual_type->data.pointer.child_type; + assert(array_type->id == TypeTableEntryIdArray); + + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, + slice_ptr_index, ""); + LLVMValueRef indices[] = { + LLVMConstNull(g->builtin_types.entry_usize->type_ref), + LLVMConstInt(g->builtin_types.entry_usize->type_ref, 0, false), + }; + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, + slice_len_index, ""); + LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->type_ref, + array_type->data.array.len, false); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); + + return cast_instruction->tmp_ptr; + } } zig_unreachable(); } @@ -3815,7 +3838,6 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst } else { end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false); } - if (want_runtime_safety) { add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); if (instruction->end) { diff --git a/src/ir.cpp b/src/ir.cpp index 3c9adab796..cc4ffb44a9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -108,6 +108,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, static TypeTableEntry *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op); static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval); static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, uint32_t new_align); +static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align); ConstExprValue *const_ptr_pointee(CodeGen *g, ConstExprValue *const_val) { assert(const_val->type->id == TypeTableEntryIdPointer); @@ -8024,6 +8025,33 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, } } + // implicit *[N]T to [*]T + if (expected_type->id == TypeTableEntryIdPointer && + expected_type->data.pointer.ptr_len == PtrLenUnknown && + actual_type->id == TypeTableEntryIdPointer && + actual_type->data.pointer.ptr_len == PtrLenSingle && + actual_type->data.pointer.child_type->id == TypeTableEntryIdArray && + types_match_const_cast_only(ira, expected_type->data.pointer.child_type, + actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk) + { + return ImplicitCastMatchResultYes; + } + + // implicit *[N]T to []T + if (is_slice(expected_type) && + actual_type->id == TypeTableEntryIdPointer && + actual_type->data.pointer.ptr_len == PtrLenSingle && + actual_type->data.pointer.child_type->id == TypeTableEntryIdArray) + { + TypeTableEntry *slice_ptr_type = expected_type->data.structure.fields[slice_ptr_index].type_entry; + assert(slice_ptr_type->id == TypeTableEntryIdPointer); + if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, + actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk) + { + return ImplicitCastMatchResultYes; + } + } + // implicit [N]T to ?[]const T if (expected_type->id == TypeTableEntryIdMaybe && is_slice(expected_type->data.maybe.child_type) && @@ -8699,6 +8727,7 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, zig_unreachable(); case CastOpErrSet: case CastOpBitCast: + case CastOpPtrOfArrayToSlice: zig_panic("TODO"); case CastOpNoop: { @@ -8786,6 +8815,63 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst } } +static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *value, TypeTableEntry *wanted_type) +{ + assert(value->value.type->id == TypeTableEntryIdPointer); + wanted_type = adjust_ptr_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment); + + if (instr_is_comptime(value)) { + ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value); + if (pointee->special != ConstValSpecialRuntime) { + IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, + source_instr->source_node, wanted_type); + result->value.type = wanted_type; + result->value.data.x_ptr.special = ConstPtrSpecialBaseArray; + result->value.data.x_ptr.mut = value->value.data.x_ptr.mut; + result->value.data.x_ptr.data.base_array.array_val = pointee; + result->value.data.x_ptr.data.base_array.elem_index = 0; + result->value.data.x_ptr.data.base_array.is_cstr = false; + return result; + } + } + + IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, + wanted_type, value, CastOpBitCast); + result->value.type = wanted_type; + return result; +} + +static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *value, TypeTableEntry *wanted_type) +{ + wanted_type = adjust_slice_align(ira->codegen, wanted_type, value->value.type->data.pointer.alignment); + + if (instr_is_comptime(value)) { + ConstExprValue *pointee = const_ptr_pointee(ira->codegen, &value->value); + if (pointee->special != ConstValSpecialRuntime) { + assert(value->value.type->id == TypeTableEntryIdPointer); + TypeTableEntry *array_type = value->value.type->data.pointer.child_type; + assert(is_slice(wanted_type)); + bool is_const = wanted_type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; + + IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->scope, + source_instr->source_node, wanted_type); + init_const_slice(ira->codegen, &result->value, pointee, 0, array_type->data.array.len, is_const); + result->value.data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = + value->value.data.x_ptr.mut; + result->value.type = wanted_type; + return result; + } + } + + IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, + wanted_type, value, CastOpPtrOfArrayToSlice); + result->value.type = wanted_type; + ir_add_alloca(ira, result, wanted_type); + return result; +} + static bool is_container(TypeTableEntry *type) { return type->id == TypeTableEntryIdStruct || type->id == TypeTableEntryIdEnum || @@ -9937,6 +10023,35 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } + // explicit *[N]T to [*]T + if (wanted_type->id == TypeTableEntryIdPointer && + wanted_type->data.pointer.ptr_len == PtrLenUnknown && + actual_type->id == TypeTableEntryIdPointer && + actual_type->data.pointer.ptr_len == PtrLenSingle && + actual_type->data.pointer.child_type->id == TypeTableEntryIdArray && + actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment && + types_match_const_cast_only(ira, wanted_type->data.pointer.child_type, + actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk) + { + return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type); + } + + // explicit *[N]T to []T + if (is_slice(wanted_type) && + actual_type->id == TypeTableEntryIdPointer && + actual_type->data.pointer.ptr_len == PtrLenSingle && + actual_type->data.pointer.child_type->id == TypeTableEntryIdArray) + { + TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry; + assert(slice_ptr_type->id == TypeTableEntryIdPointer); + if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type, + actual_type->data.pointer.child_type->data.array.child_type, source_node).id == ConstCastResultIdOk) + { + return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type); + } + } + + // explicit cast from child type of maybe type to maybe type if (wanted_type->id == TypeTableEntryIdMaybe) { TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type; @@ -13150,6 +13265,13 @@ static TypeTableEntry *adjust_ptr_align(CodeGen *g, TypeTableEntry *ptr_type, ui ptr_type->data.pointer.bit_offset, ptr_type->data.pointer.unaligned_bit_count); } +static TypeTableEntry *adjust_slice_align(CodeGen *g, TypeTableEntry *slice_type, uint32_t new_align) { + assert(is_slice(slice_type)); + TypeTableEntry *ptr_type = adjust_ptr_align(g, slice_type->data.structure.fields[slice_ptr_index].type_entry, + new_align); + return get_slice_type(g, ptr_type); +} + static TypeTableEntry *adjust_ptr_len(CodeGen *g, TypeTableEntry *ptr_type, PtrLen ptr_len) { assert(ptr_type->id == TypeTableEntryIdPointer); return get_pointer_to_type_extra(g, diff --git a/test/cases/cast.zig b/test/cases/cast.zig index 7358a4ffd8..c3ef24cd78 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -384,3 +384,19 @@ test "const slice widen cast" { assert(@bitCast(u32, bytes) == 0x12121212); } + +test "single-item pointer of array to slice and to unknown length pointer" { + testCastPtrOfArrayToSliceAndPtr(); + comptime testCastPtrOfArrayToSliceAndPtr(); +} + +fn testCastPtrOfArrayToSliceAndPtr() void { + var array = "ao" ++ "eu"; // TODO https://github.com/ziglang/zig/issues/1076 + const x: [*]u8 = &array; + x[0] += 1; + assert(mem.eql(u8, array[0..], "boeu")); + const y: []u8 = &array; + y[0] += 1; + assert(mem.eql(u8, array[0..], "coeu")); +} + -- cgit v1.2.3 From 6edd81109d16178f1dc688dacee4b38964b617c4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Jun 2018 00:15:23 -0400 Subject: nullable pointers follow const-casting rules any *T -> ?*T cast is allowed implicitly, even when it occurs deep inside the type, and the cast is a no-op at runtime. in order to add this I had to make the comptime value representation of nullable pointers the same as the comptime value representation of normal pointers, so that we don't have to do any recursive transformation of values when doing this kind of cast. --- src/all_types.hpp | 5 +- src/analyze.cpp | 280 ++++++++++++++++++++++++++++------------------------ src/codegen.cpp | 158 +++++++++++++++-------------- src/ir.cpp | 121 +++++++++++++++-------- test/cases/cast.zig | 10 +- 5 files changed, 322 insertions(+), 252 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index c671682363..14a44ea768 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -144,6 +144,9 @@ enum ConstPtrSpecial { // understand the value of pointee at compile time. However, we will still // emit a binary with a compile time known address. // In this case index is the numeric address value. + // We also use this for null pointer. We need the data layout for ConstCastOnly == true + // types to be the same, so all nullables of pointer types use x_ptr + // instead of x_nullable ConstPtrSpecialHardCodedAddr, // This means that the pointer represents memory of assigning to _. // That is, storing discards the data, and loading is invalid. @@ -251,7 +254,7 @@ struct ConstExprValue { bool x_bool; ConstBoundFnValue x_bound_fn; TypeTableEntry *x_type; - ConstExprValue *x_maybe; + ConstExprValue *x_nullable; ConstErrValue x_err_union; ErrorTableEntry *x_err_set; BigInt x_enum_tag; diff --git a/src/analyze.cpp b/src/analyze.cpp index 84f1473ea1..16b2cb0590 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4578,6 +4578,52 @@ bool fn_type_id_eql(FnTypeId *a, FnTypeId *b) { return true; } +static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { + uint32_t hash_val = 0; + switch (const_val->data.x_ptr.mut) { + case ConstPtrMutRuntimeVar: + hash_val += (uint32_t)3500721036; + break; + case ConstPtrMutComptimeConst: + hash_val += (uint32_t)4214318515; + break; + case ConstPtrMutComptimeVar: + hash_val += (uint32_t)1103195694; + break; + } + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + hash_val += (uint32_t)2478261866; + hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee); + return hash_val; + case ConstPtrSpecialBaseArray: + hash_val += (uint32_t)1764906839; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); + hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); + hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492; + return hash_val; + case ConstPtrSpecialBaseStruct: + hash_val += (uint32_t)3518317043; + hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); + hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); + return hash_val; + case ConstPtrSpecialHardCodedAddr: + hash_val += (uint32_t)4048518294; + hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); + return hash_val; + case ConstPtrSpecialDiscard: + hash_val += 2010123162; + return hash_val; + case ConstPtrSpecialFunction: + hash_val += (uint32_t)2590901619; + hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); + return hash_val; + } + zig_unreachable(); +} + static uint32_t hash_const_val(ConstExprValue *const_val) { assert(const_val->special == ConstValSpecialStatic); switch (const_val->type->id) { @@ -4646,51 +4692,7 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { assert(const_val->data.x_ptr.special == ConstPtrSpecialFunction); return 3677364617 ^ hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); case TypeTableEntryIdPointer: - { - uint32_t hash_val = 0; - switch (const_val->data.x_ptr.mut) { - case ConstPtrMutRuntimeVar: - hash_val += (uint32_t)3500721036; - break; - case ConstPtrMutComptimeConst: - hash_val += (uint32_t)4214318515; - break; - case ConstPtrMutComptimeVar: - hash_val += (uint32_t)1103195694; - break; - } - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - hash_val += (uint32_t)2478261866; - hash_val += hash_ptr(const_val->data.x_ptr.data.ref.pointee); - return hash_val; - case ConstPtrSpecialBaseArray: - hash_val += (uint32_t)1764906839; - hash_val += hash_ptr(const_val->data.x_ptr.data.base_array.array_val); - hash_val += hash_size(const_val->data.x_ptr.data.base_array.elem_index); - hash_val += const_val->data.x_ptr.data.base_array.is_cstr ? 1297263887 : 200363492; - return hash_val; - case ConstPtrSpecialBaseStruct: - hash_val += (uint32_t)3518317043; - hash_val += hash_ptr(const_val->data.x_ptr.data.base_struct.struct_val); - hash_val += hash_size(const_val->data.x_ptr.data.base_struct.field_index); - return hash_val; - case ConstPtrSpecialHardCodedAddr: - hash_val += (uint32_t)4048518294; - hash_val += hash_size(const_val->data.x_ptr.data.hard_coded_addr.addr); - return hash_val; - case ConstPtrSpecialDiscard: - hash_val += 2010123162; - return hash_val; - case ConstPtrSpecialFunction: - hash_val += (uint32_t)2590901619; - hash_val += hash_ptr(const_val->data.x_ptr.data.fn.fn_entry); - return hash_val; - } - zig_unreachable(); - } + return hash_const_val_ptr(const_val); case TypeTableEntryIdPromise: // TODO better hashing algorithm return 223048345; @@ -4708,10 +4710,14 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { // TODO better hashing algorithm return 2709806591; case TypeTableEntryIdMaybe: - if (const_val->data.x_maybe) { - return hash_const_val(const_val->data.x_maybe) * 1992916303; + if (get_codegen_ptr_type(const_val->type) != nullptr) { + return hash_const_val(const_val) * 1992916303; } else { - return 4016830364; + if (const_val->data.x_nullable) { + return hash_const_val(const_val->data.x_nullable) * 1992916303; + } else { + return 4016830364; + } } case TypeTableEntryIdErrorUnion: // TODO better hashing algorithm @@ -4812,9 +4818,11 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { return false; case TypeTableEntryIdMaybe: - if (value->data.x_maybe == nullptr) + if (get_codegen_ptr_type(value->type) != nullptr) + return value->data.x_ptr.mut == ConstPtrMutComptimeVar; + if (value->data.x_nullable == nullptr) return false; - return can_mutate_comptime_var_state(value->data.x_maybe); + return can_mutate_comptime_var_state(value->data.x_nullable); case TypeTableEntryIdErrorUnion: if (value->data.x_err_union.err != nullptr) @@ -5340,6 +5348,52 @@ bool ir_get_var_is_comptime(VariableTableEntry *var) { return var->is_comptime->value.data.x_bool; } +bool const_values_equal_ptr(ConstExprValue *a, ConstExprValue *b) { + if (a->data.x_ptr.special != b->data.x_ptr.special) + return false; + if (a->data.x_ptr.mut != b->data.x_ptr.mut) + return false; + switch (a->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee) + return false; + return true; + case ConstPtrSpecialBaseArray: + if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val && + a->data.x_ptr.data.base_array.array_val->global_refs != + b->data.x_ptr.data.base_array.array_val->global_refs) + { + return false; + } + if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index) + return false; + if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr) + return false; + return true; + case ConstPtrSpecialBaseStruct: + if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val && + a->data.x_ptr.data.base_struct.struct_val->global_refs != + b->data.x_ptr.data.base_struct.struct_val->global_refs) + { + return false; + } + if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) + return false; + return true; + case ConstPtrSpecialHardCodedAddr: + if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) + return false; + return true; + case ConstPtrSpecialDiscard: + return true; + case ConstPtrSpecialFunction: + return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; + } + zig_unreachable(); +} + bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { assert(a->type->id == b->type->id); assert(a->special == ConstValSpecialStatic); @@ -5391,49 +5445,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { return bigint_cmp(&a->data.x_bigint, &b->data.x_bigint) == CmpEQ; case TypeTableEntryIdPointer: case TypeTableEntryIdFn: - if (a->data.x_ptr.special != b->data.x_ptr.special) - return false; - if (a->data.x_ptr.mut != b->data.x_ptr.mut) - return false; - switch (a->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - if (a->data.x_ptr.data.ref.pointee != b->data.x_ptr.data.ref.pointee) - return false; - return true; - case ConstPtrSpecialBaseArray: - if (a->data.x_ptr.data.base_array.array_val != b->data.x_ptr.data.base_array.array_val && - a->data.x_ptr.data.base_array.array_val->global_refs != - b->data.x_ptr.data.base_array.array_val->global_refs) - { - return false; - } - if (a->data.x_ptr.data.base_array.elem_index != b->data.x_ptr.data.base_array.elem_index) - return false; - if (a->data.x_ptr.data.base_array.is_cstr != b->data.x_ptr.data.base_array.is_cstr) - return false; - return true; - case ConstPtrSpecialBaseStruct: - if (a->data.x_ptr.data.base_struct.struct_val != b->data.x_ptr.data.base_struct.struct_val && - a->data.x_ptr.data.base_struct.struct_val->global_refs != - b->data.x_ptr.data.base_struct.struct_val->global_refs) - { - return false; - } - if (a->data.x_ptr.data.base_struct.field_index != b->data.x_ptr.data.base_struct.field_index) - return false; - return true; - case ConstPtrSpecialHardCodedAddr: - if (a->data.x_ptr.data.hard_coded_addr.addr != b->data.x_ptr.data.hard_coded_addr.addr) - return false; - return true; - case ConstPtrSpecialDiscard: - return true; - case ConstPtrSpecialFunction: - return a->data.x_ptr.data.fn.fn_entry == b->data.x_ptr.data.fn.fn_entry; - } - zig_unreachable(); + return const_values_equal_ptr(a, b); case TypeTableEntryIdArray: zig_panic("TODO"); case TypeTableEntryIdStruct: @@ -5449,10 +5461,12 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { case TypeTableEntryIdNull: zig_panic("TODO"); case TypeTableEntryIdMaybe: - if (a->data.x_maybe == nullptr || b->data.x_maybe == nullptr) { - return (a->data.x_maybe == nullptr && b->data.x_maybe == nullptr); + if (get_codegen_ptr_type(a->type) != nullptr) + return const_values_equal_ptr(a, b); + if (a->data.x_nullable == nullptr || b->data.x_nullable == nullptr) { + return (a->data.x_nullable == nullptr && b->data.x_nullable == nullptr); } else { - return const_values_equal(a->data.x_maybe, b->data.x_maybe); + return const_values_equal(a->data.x_nullable, b->data.x_nullable); } case TypeTableEntryIdErrorUnion: zig_panic("TODO"); @@ -5525,6 +5539,41 @@ void eval_min_max_value(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue * } } +void render_const_val_ptr(CodeGen *g, Buf *buf, ConstExprValue *const_val, TypeTableEntry *type_entry) { + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + zig_unreachable(); + case ConstPtrSpecialRef: + case ConstPtrSpecialBaseStruct: + buf_appendf(buf, "*"); + render_const_value(g, buf, const_ptr_pointee(g, const_val)); + return; + case ConstPtrSpecialBaseArray: + if (const_val->data.x_ptr.data.base_array.is_cstr) { + buf_appendf(buf, "*(c str lit)"); + return; + } else { + buf_appendf(buf, "*"); + render_const_value(g, buf, const_ptr_pointee(g, const_val)); + return; + } + case ConstPtrSpecialHardCodedAddr: + buf_appendf(buf, "(*%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name), + const_val->data.x_ptr.data.hard_coded_addr.addr); + return; + case ConstPtrSpecialDiscard: + buf_append_str(buf, "*_"); + return; + case ConstPtrSpecialFunction: + { + FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry; + buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); + return; + } + } + zig_unreachable(); +} + void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { switch (const_val->special) { case ConstValSpecialRuntime: @@ -5601,38 +5650,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { return; } case TypeTableEntryIdPointer: - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - zig_unreachable(); - case ConstPtrSpecialRef: - case ConstPtrSpecialBaseStruct: - buf_appendf(buf, "&"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); - return; - case ConstPtrSpecialBaseArray: - if (const_val->data.x_ptr.data.base_array.is_cstr) { - buf_appendf(buf, "&(c str lit)"); - return; - } else { - buf_appendf(buf, "&"); - render_const_value(g, buf, const_ptr_pointee(g, const_val)); - return; - } - case ConstPtrSpecialHardCodedAddr: - buf_appendf(buf, "(&%s)(%" ZIG_PRI_x64 ")", buf_ptr(&type_entry->data.pointer.child_type->name), - const_val->data.x_ptr.data.hard_coded_addr.addr); - return; - case ConstPtrSpecialDiscard: - buf_append_str(buf, "&_"); - return; - case ConstPtrSpecialFunction: - { - FnTableEntry *fn_entry = const_val->data.x_ptr.data.fn.fn_entry; - buf_appendf(buf, "@ptrCast(%s, %s)", buf_ptr(&const_val->type->name), buf_ptr(&fn_entry->symbol_name)); - return; - } - } - zig_unreachable(); + return render_const_val_ptr(g, buf, const_val, type_entry); case TypeTableEntryIdBlock: { AstNode *node = const_val->data.x_block->source_node; @@ -5692,8 +5710,10 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { } case TypeTableEntryIdMaybe: { - if (const_val->data.x_maybe) { - render_const_value(g, buf, const_val->data.x_maybe); + if (get_codegen_ptr_type(const_val->type) != nullptr) + return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); + if (const_val->data.x_nullable) { + render_const_value(g, buf, const_val->data.x_nullable); } else { buf_appendf(buf, "null"); } diff --git a/src/codegen.cpp b/src/codegen.cpp index fab2ad659e..65b465a519 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5020,6 +5020,79 @@ static bool is_llvm_value_unnamed_type(TypeTableEntry *type_entry, LLVMValueRef return LLVMTypeOf(val) != type_entry->type_ref; } +static LLVMValueRef gen_const_val_ptr(CodeGen *g, ConstExprValue *const_val, const char *name) { + render_const_val_global(g, const_val, name); + switch (const_val->data.x_ptr.special) { + case ConstPtrSpecialInvalid: + case ConstPtrSpecialDiscard: + zig_unreachable(); + case ConstPtrSpecialRef: + { + ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee; + render_const_val(g, pointee, ""); + render_const_val_global(g, pointee, ""); + ConstExprValue *other_val = pointee; + const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + case ConstPtrSpecialBaseArray: + { + ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; + size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; + assert(array_const_val->type->id == TypeTableEntryIdArray); + if (array_const_val->type->zero_bits) { + // make this a null pointer + TypeTableEntry *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, + elem_index); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialBaseStruct: + { + ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val; + assert(struct_const_val->type->id == TypeTableEntryIdStruct); + if (struct_const_val->type->zero_bits) { + // make this a null pointer + TypeTableEntry *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index; + size_t gen_field_index = + struct_const_val->type->data.structure.fields[src_field_index].gen_index; + LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val, + gen_field_index); + LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); + const_val->global_refs->llvm_value = ptr_val; + render_const_val_global(g, const_val, ""); + return ptr_val; + } + case ConstPtrSpecialHardCodedAddr: + { + uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr; + TypeTableEntry *usize = g->builtin_types.entry_usize; + const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false), + const_val->type->type_ref); + render_const_val_global(g, const_val, ""); + return const_val->global_refs->llvm_value; + } + case ConstPtrSpecialFunction: + return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref); + } + zig_unreachable(); +} + static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const char *name) { TypeTableEntry *type_entry = const_val->type; assert(!type_entry->zero_bits); @@ -5068,19 +5141,15 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c { TypeTableEntry *child_type = type_entry->data.maybe.child_type; if (child_type->zero_bits) { - return LLVMConstInt(LLVMInt1Type(), const_val->data.x_maybe ? 1 : 0, false); + return LLVMConstInt(LLVMInt1Type(), const_val->data.x_nullable ? 1 : 0, false); } else if (type_is_codegen_pointer(child_type)) { - if (const_val->data.x_maybe) { - return gen_const_val(g, const_val->data.x_maybe, ""); - } else { - return LLVMConstNull(child_type->type_ref); - } + return gen_const_val_ptr(g, const_val, name); } else { LLVMValueRef child_val; LLVMValueRef maybe_val; bool make_unnamed_struct; - if (const_val->data.x_maybe) { - child_val = gen_const_val(g, const_val->data.x_maybe, ""); + if (const_val->data.x_nullable) { + child_val = gen_const_val(g, const_val->data.x_nullable, ""); maybe_val = LLVMConstAllOnes(LLVMInt1Type()); make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val); @@ -5270,78 +5339,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c assert(const_val->data.x_ptr.mut == ConstPtrMutComptimeConst); return fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry); case TypeTableEntryIdPointer: - { - render_const_val_global(g, const_val, name); - switch (const_val->data.x_ptr.special) { - case ConstPtrSpecialInvalid: - case ConstPtrSpecialDiscard: - zig_unreachable(); - case ConstPtrSpecialRef: - { - ConstExprValue *pointee = const_val->data.x_ptr.data.ref.pointee; - render_const_val(g, pointee, ""); - render_const_val_global(g, pointee, ""); - ConstExprValue *other_val = pointee; - const_val->global_refs->llvm_value = LLVMConstBitCast(other_val->global_refs->llvm_global, const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->global_refs->llvm_value; - } - case ConstPtrSpecialBaseArray: - { - ConstExprValue *array_const_val = const_val->data.x_ptr.data.base_array.array_val; - size_t elem_index = const_val->data.x_ptr.data.base_array.elem_index; - assert(array_const_val->type->id == TypeTableEntryIdArray); - if (array_const_val->type->zero_bits) { - // make this a null pointer - TypeTableEntry *usize = g->builtin_types.entry_usize; - const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), - const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->global_refs->llvm_value; - } - LLVMValueRef uncasted_ptr_val = gen_const_ptr_array_recursive(g, array_const_val, - elem_index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); - const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); - return ptr_val; - } - case ConstPtrSpecialBaseStruct: - { - ConstExprValue *struct_const_val = const_val->data.x_ptr.data.base_struct.struct_val; - assert(struct_const_val->type->id == TypeTableEntryIdStruct); - if (struct_const_val->type->zero_bits) { - // make this a null pointer - TypeTableEntry *usize = g->builtin_types.entry_usize; - const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstNull(usize->type_ref), - const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->global_refs->llvm_value; - } - size_t src_field_index = const_val->data.x_ptr.data.base_struct.field_index; - size_t gen_field_index = - struct_const_val->type->data.structure.fields[src_field_index].gen_index; - LLVMValueRef uncasted_ptr_val = gen_const_ptr_struct_recursive(g, struct_const_val, - gen_field_index); - LLVMValueRef ptr_val = LLVMConstBitCast(uncasted_ptr_val, const_val->type->type_ref); - const_val->global_refs->llvm_value = ptr_val; - render_const_val_global(g, const_val, ""); - return ptr_val; - } - case ConstPtrSpecialHardCodedAddr: - { - uint64_t addr_value = const_val->data.x_ptr.data.hard_coded_addr.addr; - TypeTableEntry *usize = g->builtin_types.entry_usize; - const_val->global_refs->llvm_value = LLVMConstIntToPtr(LLVMConstInt(usize->type_ref, addr_value, false), - const_val->type->type_ref); - render_const_val_global(g, const_val, ""); - return const_val->global_refs->llvm_value; - } - case ConstPtrSpecialFunction: - return LLVMConstBitCast(fn_llvm_value(g, const_val->data.x_ptr.data.fn.fn_entry), const_val->type->type_ref); - } - } - zig_unreachable(); + return gen_const_val_ptr(g, const_val, name); case TypeTableEntryIdErrorUnion: { TypeTableEntry *payload_type = type_entry->data.error_union.payload_type; diff --git a/src/ir.cpp b/src/ir.cpp index e62ec71875..13ecfd4233 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -62,6 +62,7 @@ enum ConstCastResultId { ConstCastResultIdType, ConstCastResultIdUnresolvedInferredErrSet, ConstCastResultIdAsyncAllocatorType, + ConstCastResultIdNullWrapPtr, }; struct ConstCastErrSetMismatch { @@ -90,6 +91,7 @@ struct ConstCastOnly { ConstCastOnly *error_union_error_set; ConstCastOnly *return_type; ConstCastOnly *async_allocator_type; + ConstCastOnly *null_wrap_ptr_child; ConstCastArg fn_arg; ConstCastArgNoAlias arg_no_alias; } data; @@ -7660,6 +7662,21 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry if (expected_type == actual_type) return result; + // * and [*] can do a const-cast-only to ?* and ?[*], respectively + if (expected_type->id == TypeTableEntryIdMaybe && + expected_type->data.maybe.child_type->id == TypeTableEntryIdPointer && + actual_type->id == TypeTableEntryIdPointer) + { + ConstCastOnly child = types_match_const_cast_only(ira, + expected_type->data.maybe.child_type, actual_type, source_node); + if (child.id != ConstCastResultIdOk) { + result.id = ConstCastResultIdNullWrapPtr; + result.data.null_wrap_ptr_child = allocate_nonzero(1); + *result.data.null_wrap_ptr_child = child; + } + return result; + } + // pointer const if (expected_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer && @@ -8741,7 +8758,8 @@ static void eval_const_expr_implicit_cast(CastOp cast_op, zig_panic("TODO"); case CastOpNoop: { - copy_const_val(const_val, other_val, other_val->special == ConstValSpecialStatic); + bool same_global_refs = other_val->special == ConstValSpecialStatic; + copy_const_val(const_val, other_val, same_global_refs); const_val->type = new_type; break; } @@ -9189,9 +9207,13 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); - const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_maybe = val; + if (get_codegen_ptr_type(wanted_type) != nullptr) { + copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); + } else { + const_instruction->base.value.data.x_nullable = val; + } + const_instruction->base.value.type = wanted_type; return &const_instruction->base; } @@ -9346,9 +9368,14 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so assert(val); IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, source_instr->scope, source_instr->source_node); - const_instruction->base.value.type = wanted_type; const_instruction->base.value.special = ConstValSpecialStatic; - const_instruction->base.value.data.x_maybe = nullptr; + if (get_codegen_ptr_type(wanted_type) != nullptr) { + const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0; + } else { + const_instruction->base.value.data.x_nullable = nullptr; + } + const_instruction->base.value.type = wanted_type; return &const_instruction->base; } @@ -10062,7 +10089,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } - // explicit cast from child type of maybe type to maybe type + // explicit cast from T to ?T + // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism if (wanted_type->id == TypeTableEntryIdMaybe) { TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type; if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk) { @@ -10113,7 +10141,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } - // explicit cast from [N]T to %[]const T + // explicit cast from [N]T to E![]const T if (wanted_type->id == TypeTableEntryIdErrorUnion && is_slice(wanted_type->data.error_union.payload_type) && actual_type->id == TypeTableEntryIdArray) @@ -10143,7 +10171,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); } - // explicit cast from T to %?T + // explicit cast from T to E!?T if (wanted_type->id == TypeTableEntryIdErrorUnion && wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe && actual_type->id != TypeTableEntryIdMaybe) @@ -10167,7 +10195,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } // explicit cast from number literal to another type - // explicit cast from number literal to &const integer + // explicit cast from number literal to *const integer if (actual_type->id == TypeTableEntryIdComptimeFloat || actual_type->id == TypeTableEntryIdComptimeInt) { @@ -10391,6 +10419,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->scope, source_instruction->source_node, child_type); copy_const_val(&result->value, pointee, ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst); + result->value.type = child_type; return result; } } @@ -10708,6 +10737,16 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { } } +static bool nullable_value_is_null(ConstExprValue *val) { + assert(val->special == ConstValSpecialStatic); + if (get_codegen_ptr_type(val->type) != nullptr) { + return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && + val->data.x_ptr.data.hard_coded_addr.addr == 0; + } else { + return val->data.x_nullable == nullptr; + } +} + static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp *bin_op_instruction) { IrInstruction *op1 = bin_op_instruction->op1->other; IrInstruction *op2 = bin_op_instruction->op2->other; @@ -10737,7 +10776,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp ConstExprValue *maybe_val = ir_resolve_const(ira, maybe_op, UndefBad); if (!maybe_val) return ira->codegen->builtin_types.entry_invalid; - bool is_null = (maybe_val->data.x_maybe == nullptr); + bool is_null = nullable_value_is_null(maybe_val); ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base); out_val->data.x_bool = (op_id == IrBinOpCmpEq) ? is_null : !is_null; return ira->codegen->builtin_types.entry_bool; @@ -12015,7 +12054,9 @@ static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_maybe = nullptr; + assert(get_codegen_ptr_type(nullable_type) != nullptr); + out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; + out_val->data.x_ptr.data.hard_coded_addr.addr = 0; return nullable_type; } IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, @@ -14207,6 +14248,9 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { IrInstruction *ptr = load_ptr_instruction->ptr->other; + if (type_is_invalid(ptr->value.type)) + return ira->codegen->builtin_types.entry_invalid; + IrInstruction *result = ir_get_deref(ira, &load_ptr_instruction->base, ptr); ir_link_new_instruction(result, &load_ptr_instruction->base); assert(result->value.type); @@ -14773,7 +14817,7 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn return ira->codegen->builtin_types.entry_invalid; ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_bool = (maybe_val->data.x_maybe != nullptr); + out_val->data.x_bool = !nullable_value_is_null(maybe_val); return ira->codegen->builtin_types.entry_bool; } @@ -14837,13 +14881,18 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, ConstExprValue *maybe_val = const_ptr_pointee(ira->codegen, val); if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - if (!maybe_val->data.x_maybe) { + if (nullable_value_is_null(maybe_val)) { ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null")); return ira->codegen->builtin_types.entry_invalid; } ConstExprValue *out_val = ir_build_const_from(ira, &unwrap_maybe_instruction->base); out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_maybe; + out_val->data.x_ptr.mut = val->data.x_ptr.mut; + if (type_is_codegen_pointer(child_type)) { + out_val->data.x_ptr.data.ref.pointee = maybe_val; + } else { + out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_nullable; + } return result_type; } } @@ -16206,12 +16255,12 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop 0, 0); fn_def_fields[6].type = get_maybe_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr)); if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) { - fn_def_fields[6].data.x_maybe = create_const_vals(1); + fn_def_fields[6].data.x_nullable = create_const_vals(1); ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name); - init_const_slice(ira->codegen, fn_def_fields[6].data.x_maybe, lib_name, 0, buf_len(fn_node->lib_name), true); + init_const_slice(ira->codegen, fn_def_fields[6].data.x_nullable, lib_name, 0, buf_len(fn_node->lib_name), true); + } else { + fn_def_fields[6].data.x_nullable = nullptr; } - else - fn_def_fields[6].data.x_maybe = nullptr; // return_type: type ensure_field_index(fn_def_val->type, "return_type", 7); fn_def_fields[7].special = ConstValSpecialStatic; @@ -16664,8 +16713,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t TypeTableEntry *type_info_enum_field_type = ir_type_info_get_type(ira, "EnumField"); - for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) - { + for (uint32_t union_field_index = 0; union_field_index < union_field_count; union_field_index++) { TypeUnionField *union_field = &type_entry->data.unionation.fields[union_field_index]; ConstExprValue *union_field_val = &union_field_array->data.x_array.s_none.elements[union_field_index]; @@ -16676,12 +16724,11 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t inner_fields[1].special = ConstValSpecialStatic; inner_fields[1].type = get_maybe_type(ira->codegen, type_info_enum_field_type); - if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef) - inner_fields[1].data.x_maybe = nullptr; - else - { - inner_fields[1].data.x_maybe = create_const_vals(1); - make_enum_field_val(inner_fields[1].data.x_maybe, union_field->enum_field, type_info_enum_field_type); + if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef) { + inner_fields[1].data.x_nullable = nullptr; + } else { + inner_fields[1].data.x_nullable = create_const_vals(1); + make_enum_field_val(inner_fields[1].data.x_nullable, union_field->enum_field, type_info_enum_field_type); } inner_fields[2].special = ConstValSpecialStatic; @@ -16737,8 +16784,7 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t init_const_slice(ira->codegen, &fields[1], struct_field_array, 0, struct_field_count, false); - for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) - { + for (uint32_t struct_field_index = 0; struct_field_index < struct_field_count; struct_field_index++) { TypeStructField *struct_field = &type_entry->data.structure.fields[struct_field_index]; ConstExprValue *struct_field_val = &struct_field_array->data.x_array.s_none.elements[struct_field_index]; @@ -16749,15 +16795,14 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t inner_fields[1].special = ConstValSpecialStatic; inner_fields[1].type = get_maybe_type(ira->codegen, ira->codegen->builtin_types.entry_usize); - if (!type_has_bits(struct_field->type_entry)) - inner_fields[1].data.x_maybe = nullptr; - else - { + if (!type_has_bits(struct_field->type_entry)) { + inner_fields[1].data.x_nullable = nullptr; + } else { size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index); - inner_fields[1].data.x_maybe = create_const_vals(1); - inner_fields[1].data.x_maybe->special = ConstValSpecialStatic; - inner_fields[1].data.x_maybe->type = ira->codegen->builtin_types.entry_usize; - bigint_init_unsigned(&inner_fields[1].data.x_maybe->data.x_bigint, byte_offset); + inner_fields[1].data.x_nullable = create_const_vals(1); + inner_fields[1].data.x_nullable->special = ConstValSpecialStatic; + inner_fields[1].data.x_nullable->type = ira->codegen->builtin_types.entry_usize; + bigint_init_unsigned(&inner_fields[1].data.x_nullable->data.x_bigint, byte_offset); } inner_fields[2].special = ConstValSpecialStatic; @@ -19008,9 +19053,6 @@ static TypeTableEntry *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstr ConstExprValue *val = ir_resolve_const(ira, target, UndefBad); if (!val) return ira->codegen->builtin_types.entry_invalid; - if (target->value.type->id == TypeTableEntryIdMaybe) { - val = val->data.x_maybe; - } if (val->type->id == TypeTableEntryIdPointer && val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { IrInstruction *result = ir_create_const(&ira->new_irb, instruction->base.scope, instruction->base.source_node, usize); @@ -19936,6 +19978,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi static TypeTableEntry *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction) { TypeTableEntry *instruction_type = ir_analyze_instruction_nocast(ira, instruction); instruction->value.type = instruction_type; + if (instruction->other) { instruction->other->value.type = instruction_type; } else { diff --git a/test/cases/cast.zig b/test/cases/cast.zig index c3ef24cd78..da3cba7d80 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -1,5 +1,6 @@ -const assert = @import("std").debug.assert; -const mem = @import("std").mem; +const std = @import("std"); +const assert = std.debug.assert; +const mem = std.mem; test "int to ptr cast" { const x = usize(13); @@ -400,3 +401,8 @@ fn testCastPtrOfArrayToSliceAndPtr() void { assert(mem.eql(u8, array[0..], "coeu")); } +test "cast *[1][*]const u8 to [*]const ?[*]const u8" { + const window_name = [1][*]const u8{c"window name"}; + const x: [*]const ?[*]const u8 = &window_name; + assert(mem.eql(u8, std.cstr.toSliceConst(??x[0]), "window name")); +} -- cgit v1.2.3 From ec1b6f66737f8c3cbc0420715c2c502c7e710081 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 9 Jun 2018 23:42:14 -0400 Subject: breaking syntax change: ??x to x.? (#1095) See #1023 This also renames Nullable/Maybe to Optional --- build.zig | 2 +- doc/codegen.md | 8 +- doc/langref.html.in | 122 ++++++++++++++-------------- example/cat/main.zig | 2 +- src-self-hosted/arg.zig | 10 +-- src-self-hosted/llvm.zig | 2 +- src-self-hosted/main.zig | 8 +- src/all_types.hpp | 44 +++++------ src/analyze.cpp | 70 ++++++++-------- src/ast_render.cpp | 6 +- src/codegen.cpp | 60 +++++++------- src/ir.cpp | 198 +++++++++++++++++++++++----------------------- src/ir_print.cpp | 16 ++-- src/parser.cpp | 21 +++-- src/tokenizer.cpp | 10 +-- src/tokenizer.hpp | 3 +- src/translate_c.cpp | 14 ++-- std/array_list.zig | 2 +- std/buf_map.zig | 6 +- std/event.zig | 4 +- std/fmt/index.zig | 6 +- std/hash_map.zig | 8 +- std/heap.zig | 4 +- std/json.zig | 12 +-- std/linked_list.zig | 8 +- std/macho.zig | 2 +- std/mem.zig | 22 +++--- std/os/child_process.zig | 18 ++--- std/os/index.zig | 4 +- std/os/linux/vdso.zig | 2 +- std/os/path.zig | 8 +- std/segmented_list.zig | 8 +- std/special/bootstrap.zig | 6 +- std/special/builtin.zig | 8 +- std/unicode.zig | 24 +++--- std/zig/ast.zig | 12 +-- std/zig/parse.zig | 35 +++++--- std/zig/parser_test.zig | 5 +- std/zig/render.zig | 25 +++--- test/cases/bugs/656.zig | 2 +- test/cases/cast.zig | 50 ++++++------ test/cases/error.zig | 2 +- test/cases/eval.zig | 2 +- test/cases/generics.zig | 2 +- test/cases/misc.zig | 2 +- test/cases/null.zig | 30 +++---- test/cases/reflection.zig | 2 +- test/cases/type_info.zig | 14 ++-- test/cases/while.zig | 12 +-- test/compile_errors.zig | 16 ++-- test/tests.zig | 12 +-- 51 files changed, 489 insertions(+), 482 deletions(-) (limited to 'src/codegen.cpp') diff --git a/build.zig b/build.zig index 08a47570ef..eada37816c 100644 --- a/build.zig +++ b/build.zig @@ -75,7 +75,7 @@ pub fn build(b: *Builder) !void { cxx_compiler, "-print-file-name=libstdc++.a", }); - const libstdcxx_path = ??mem.split(libstdcxx_path_padded, "\r\n").next(); + const libstdcxx_path = mem.split(libstdcxx_path_padded, "\r\n").next().?; if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) { warn( \\Unable to determine path to libstdc++.a diff --git a/doc/codegen.md b/doc/codegen.md index 02406fae82..65f12f4875 100644 --- a/doc/codegen.md +++ b/doc/codegen.md @@ -6,7 +6,7 @@ Every type has a "handle". If a type is a simple primitive type such as i32 or f64, the handle is "by value", meaning that we pass around the value itself when we refer to a value of that type. -If a type is a container, error union, maybe type, slice, or array, then its +If a type is a container, error union, optional type, slice, or array, then its handle is a pointer, and everywhere we refer to a value of this type we refer to a pointer. @@ -19,7 +19,7 @@ Error union types are represented as: payload: T, } -Maybe types are represented as: +Optional types are represented as: struct { payload: T, @@ -28,6 +28,6 @@ Maybe types are represented as: ## Data Optimizations -Maybe pointer types are special: the 0x0 pointer value is used to represent a -null pointer. Thus, instead of the struct above, maybe pointer types are +Optional pointer types are special: the 0x0 pointer value is used to represent a +null pointer. Thus, instead of the struct above, optional pointer types are represented as a `usize` in codegen and the handle is by value. diff --git a/doc/langref.html.in b/doc/langref.html.in index 6a1f1c3102..4c4a637095 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -156,18 +156,18 @@ pub fn main() void { true or false, !true); - // nullable - var nullable_value: ?[]const u8 = null; - assert(nullable_value == null); + // optional + var optional_value: ?[]const u8 = null; + assert(optional_value == null); - warn("\nnullable 1\ntype: {}\nvalue: {}\n", - @typeName(@typeOf(nullable_value)), nullable_value); + warn("\noptional 1\ntype: {}\nvalue: {}\n", + @typeName(@typeOf(optional_value)), optional_value); - nullable_value = "hi"; - assert(nullable_value != null); + optional_value = "hi"; + assert(optional_value != null); - warn("\nnullable 2\ntype: {}\nvalue: {}\n", - @typeName(@typeOf(nullable_value)), nullable_value); + warn("\noptional 2\ntype: {}\nvalue: {}\n", + @typeName(@typeOf(optional_value)), optional_value); // error union var number_or_error: error!i32 = error.ArgNotFound; @@ -428,7 +428,7 @@ pub fn main() void { null - used to set a nullable type to null + used to set an optional type to null undefined @@ -440,7 +440,7 @@ pub fn main() void { - {#see_also|Nullables|this#} + {#see_also|Optionals|this#} {#header_close#} {#header_open|String Literals#} {#code_begin|test#} @@ -988,7 +988,7 @@ a ^= b

a ?? b
    -
  • {#link|Nullables#}
  • +
  • {#link|Optionals#}
If a is null, @@ -1003,10 +1003,10 @@ unwrapped == 1234 -
??a
+
a.?
    -
  • {#link|Nullables#}
  • +
  • {#link|Optionals#}
@@ -1015,7 +1015,7 @@ unwrapped == 1234
const value: ?u32 = 5678;
-??value == 5678
+value.? == 5678 @@ -1103,7 +1103,7 @@ unwrapped == 1234
a == null
    -
  • {#link|Nullables#}
  • +
  • {#link|Optionals#}
@@ -1267,8 +1267,8 @@ x.* == 1234
{#header_open|Precedence#}
x() x[] x.y
 a!b
-!x -x -%x ~x &x ?x ??x
-x{} x.*
+!x -x -%x ~x &x ?x
+x{} x.* x.?
 ! * / % ** *%
 + - ++ +% -%
 << >>
@@ -1483,17 +1483,17 @@ test "volatile" {
     assert(@typeOf(mmio_ptr) == *volatile u8);
 }
 
-test "nullable pointers" {
-    // Pointers cannot be null. If you want a null pointer, use the nullable
-    // prefix `?` to make the pointer type nullable.
+test "optional pointers" {
+    // Pointers cannot be null. If you want a null pointer, use the optional
+    // prefix `?` to make the pointer type optional.
     var ptr: ?*i32 = null;
 
     var x: i32 = 1;
     ptr = &x;
 
-    assert((??ptr).* == 1);
+    assert(ptr.?.* == 1);
 
-    // Nullable pointers are the same size as normal pointers, because pointer
+    // Optional pointers are the same size as normal pointers, because pointer
     // value 0 is used as the null value.
     assert(@sizeOf(?*i32) == @sizeOf(*i32));
 }
@@ -1832,7 +1832,7 @@ test "linked list" {
         .last = &node,
         .len = 1,
     };
-    assert((??list2.first).data == 1234);
+    assert(list2.first.?.data == 1234);
 }
       {#code_end#}
       {#see_also|comptime|@fieldParentPtr#}
@@ -2270,7 +2270,7 @@ fn rangeHasNumber(begin: usize, end: usize, number: usize) bool {
 }
 
 test "while null capture" {
-    // Just like if expressions, while loops can take a nullable as the
+    // Just like if expressions, while loops can take an optional as the
     // condition and capture the payload. When null is encountered the loop
     // exits.
     var sum1: u32 = 0;
@@ -2280,7 +2280,7 @@ test "while null capture" {
     }
     assert(sum1 == 3);
 
-    // The else branch is allowed on nullable iteration. In this case, it will
+    // The else branch is allowed on optional iteration. In this case, it will
     // be executed on the first null value encountered.
     var sum2: u32 = 0;
     numbers_left = 3;
@@ -2340,7 +2340,7 @@ fn typeNameLength(comptime T: type) usize {
     return @typeName(T).len;
 }
       {#code_end#}
-      {#see_also|if|Nullables|Errors|comptime|unreachable#}
+      {#see_also|if|Optionals|Errors|comptime|unreachable#}
       {#header_close#}
       {#header_open|for#}
       {#code_begin|test|for#}
@@ -2400,7 +2400,7 @@ test "for else" {
         if (value == null) {
             break 9;
         } else {
-            sum += ??value;
+            sum += value.?;
         }
     } else blk: {
         assert(sum == 7);
@@ -2461,7 +2461,7 @@ test "if boolean" {
     assert(result == 47);
 }
 
-test "if nullable" {
+test "if optional" {
     // If expressions test for null.
 
     const a: ?u32 = 0;
@@ -2544,7 +2544,7 @@ test "if error union" {
     }
 }
       {#code_end#}
-      {#see_also|Nullables|Errors#}
+      {#see_also|Optionals|Errors#}
       {#header_close#}
       {#header_open|defer#}
       {#code_begin|test|defer#}
@@ -3167,24 +3167,24 @@ test "inferred error set" {
       

TODO

{#header_close#} {#header_close#} - {#header_open|Nullables#} + {#header_open|Optionals#}

One area that Zig provides safety without compromising efficiency or - readability is with the nullable type. + readability is with the optional type.

- The question mark symbolizes the nullable type. You can convert a type to a nullable + The question mark symbolizes the optional type. You can convert a type to an optional type by putting a question mark in front of it, like this:

{#code_begin|syntax#} // normal integer const normal_int: i32 = 1234; -// nullable integer -const nullable_int: ?i32 = 5678; +// optional integer +const optional_int: ?i32 = 5678; {#code_end#}

- Now the variable nullable_int could be an i32, or null. + Now the variable optional_int could be an i32, or null.

Instead of integers, let's talk about pointers. Null references are the source of many runtime @@ -3193,8 +3193,8 @@ const nullable_int: ?i32 = 5678;

Zig does not have them.

- Instead, you can use a nullable pointer. This secretly compiles down to a normal pointer, - since we know we can use 0 as the null value for the nullable type. But the compiler + Instead, you can use an optional pointer. This secretly compiles down to a normal pointer, + since we know we can use 0 as the null value for the optional type. But the compiler can check your work and make sure you don't assign null to something that can't be null.

@@ -3226,7 +3226,7 @@ fn doAThing() ?*Foo {

Here, Zig is at least as convenient, if not more, than C. And, the type of "ptr" is *u8 not ?*u8. The ?? operator - unwrapped the nullable type and therefore ptr is guaranteed to be non-null everywhere + unwrapped the optional type and therefore ptr is guaranteed to be non-null everywhere it is used in the function.

@@ -3245,10 +3245,10 @@ fn doAThing() ?*Foo { In Zig you can accomplish the same thing:

{#code_begin|syntax#} -fn doAThing(nullable_foo: ?*Foo) void { +fn doAThing(optional_foo: ?*Foo) void { // do some stuff - if (nullable_foo) |foo| { + if (optional_foo) |foo| { doSomethingWithFoo(foo); } @@ -3257,7 +3257,7 @@ fn doAThing(nullable_foo: ?*Foo) void { {#code_end#}

Once again, the notable thing here is that inside the if block, - foo is no longer a nullable pointer, it is a pointer, which + foo is no longer an optional pointer, it is a pointer, which cannot be null.

@@ -3267,20 +3267,20 @@ fn doAThing(nullable_foo: ?*Foo) void { The optimizer can sometimes make better decisions knowing that pointer arguments cannot be null.

- {#header_open|Nullable Type#} -

A nullable is created by putting ? in front of a type. You can use compile-time - reflection to access the child type of a nullable:

+ {#header_open|Optional Type#} +

An optional is created by putting ? in front of a type. You can use compile-time + reflection to access the child type of an optional:

{#code_begin|test#} const assert = @import("std").debug.assert; -test "nullable type" { - // Declare a nullable and implicitly cast from null: +test "optional type" { + // Declare an optional and implicitly cast from null: var foo: ?i32 = null; - // Implicitly cast from child type of a nullable + // Implicitly cast from child type of an optional foo = 1234; - // Use compile-time reflection to access the child type of the nullable: + // Use compile-time reflection to access the child type of the optional: comptime assert(@typeOf(foo).Child == i32); } {#code_end#} @@ -4888,7 +4888,7 @@ pub const TypeId = enum { ComptimeInt, Undefined, Null, - Nullable, + Optional, ErrorUnion, Error, Enum, @@ -4922,7 +4922,7 @@ pub const TypeInfo = union(TypeId) { ComptimeInt: void, Undefined: void, Null: void, - Nullable: Nullable, + Optional: Optional, ErrorUnion: ErrorUnion, ErrorSet: ErrorSet, Enum: Enum, @@ -4975,7 +4975,7 @@ pub const TypeInfo = union(TypeId) { defs: []Definition, }; - pub const Nullable = struct { + pub const Optional = struct { child: type, }; @@ -5366,8 +5366,8 @@ comptime {

At compile-time:

{#code_begin|test_err|unable to unwrap null#} comptime { - const nullable_number: ?i32 = null; - const number = ??nullable_number; + const optional_number: ?i32 = null; + const number = optional_number.?; } {#code_end#}

At runtime crashes with the message attempt to unwrap null and a stack trace.

@@ -5376,9 +5376,9 @@ comptime { {#code_begin|exe|test#} const warn = @import("std").debug.warn; pub fn main() void { - const nullable_number: ?i32 = null; + const optional_number: ?i32 = null; - if (nullable_number) |number| { + if (optional_number) |number| { warn("got number: {}\n", number); } else { warn("it's null\n"); @@ -5939,9 +5939,9 @@ AsmInputItem = "[" Symbol "]" String "(" Expression ")" AsmClobbers= ":" list(String, ",") -UnwrapExpression = BoolOrExpression (UnwrapNullable | UnwrapError) | BoolOrExpression +UnwrapExpression = BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression -UnwrapNullable = "??" Expression +UnwrapOptional = "??" Expression UnwrapError = "catch" option("|" Symbol "|") Expression @@ -6015,12 +6015,10 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%" PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression -SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | PtrDerefExpression) +SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ".*" | ".?") FieldAccessExpression = "." Symbol -PtrDerefExpression = ".*" - FnCallExpression = "(" list(Expression, ",") ")" ArrayAccessExpression = "[" Expression "]" @@ -6033,7 +6031,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",") StructLiteralField = "." Symbol "=" Expression -PrefixOp = "!" | "-" | "~" | (("*" | "[*]") option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await" +PrefixOp = "!" | "-" | "~" | (("*" | "[*]") option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "-%" | "try" | "await" PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType diff --git a/example/cat/main.zig b/example/cat/main.zig index 1b34cb22eb..27690d2695 100644 --- a/example/cat/main.zig +++ b/example/cat/main.zig @@ -7,7 +7,7 @@ const allocator = std.debug.global_allocator; pub fn main() !void { var args_it = os.args(); - const exe = try unwrapArg(??args_it.next(allocator)); + const exe = try unwrapArg(args_it.next(allocator).?); var catted_anything = false; var stdout_file = try io.getStdOut(); diff --git a/src-self-hosted/arg.zig b/src-self-hosted/arg.zig index df2c04ef1f..dc89483213 100644 --- a/src-self-hosted/arg.zig +++ b/src-self-hosted/arg.zig @@ -99,7 +99,7 @@ pub const Args = struct { error.ArgumentNotInAllowedSet => { std.debug.warn("argument '{}' is invalid for flag '{}'\n", args[i], arg); std.debug.warn("allowed options are "); - for (??flag.allowed_set) |possible| { + for (flag.allowed_set.?) |possible| { std.debug.warn("'{}' ", possible); } std.debug.warn("\n"); @@ -276,14 +276,14 @@ test "parse arguments" { debug.assert(!args.present("help2")); debug.assert(!args.present("init")); - debug.assert(mem.eql(u8, ??args.single("build-file"), "build.zig")); - debug.assert(mem.eql(u8, ??args.single("color"), "on")); + debug.assert(mem.eql(u8, args.single("build-file").?, "build.zig")); + debug.assert(mem.eql(u8, args.single("color").?, "on")); - const objects = ??args.many("object"); + const objects = args.many("object").?; debug.assert(mem.eql(u8, objects[0], "obj1")); debug.assert(mem.eql(u8, objects[1], "obj2")); - debug.assert(mem.eql(u8, ??args.single("library"), "lib2")); + debug.assert(mem.eql(u8, args.single("library").?, "lib2")); const pos = args.positionals.toSliceConst(); debug.assert(mem.eql(u8, pos[0], "build")); diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index 16c359adcf..391a92cd63 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -8,6 +8,6 @@ pub const ContextRef = removeNullability(c.LLVMContextRef); pub const BuilderRef = removeNullability(c.LLVMBuilderRef); fn removeNullability(comptime T: type) type { - comptime assert(@typeId(T) == builtin.TypeId.Nullable); + comptime assert(@typeId(T) == builtin.TypeId.Optional); return T.Child; } diff --git a/src-self-hosted/main.zig b/src-self-hosted/main.zig index a264b5484a..64734f077a 100644 --- a/src-self-hosted/main.zig +++ b/src-self-hosted/main.zig @@ -490,7 +490,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo try stderr.print("encountered --pkg-end with no matching --pkg-begin\n"); os.exit(1); } - cur_pkg = ??cur_pkg.parent; + cur_pkg = cur_pkg.parent.?; } } @@ -514,7 +514,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo }, } - const basename = os.path.basename(??in_file); + const basename = os.path.basename(in_file.?); var it = mem.split(basename, "."); const root_name = it.next() ?? { try stderr.write("file name cannot be empty\n"); @@ -523,12 +523,12 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo const asm_a = flags.many("assembly"); const obj_a = flags.many("object"); - if (in_file == null and (obj_a == null or (??obj_a).len == 0) and (asm_a == null or (??asm_a).len == 0)) { + if (in_file == null and (obj_a == null or obj_a.?.len == 0) and (asm_a == null or asm_a.?.len == 0)) { try stderr.write("Expected source file argument or at least one --object or --assembly argument\n"); os.exit(1); } - if (out_type == Module.Kind.Obj and (obj_a != null and (??obj_a).len != 0)) { + if (out_type == Module.Kind.Obj and (obj_a != null and obj_a.?.len != 0)) { try stderr.write("When building an object file, --object arguments are invalid\n"); os.exit(1); } diff --git a/src/all_types.hpp b/src/all_types.hpp index 14a44ea768..2a5a0ad740 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -145,8 +145,8 @@ enum ConstPtrSpecial { // emit a binary with a compile time known address. // In this case index is the numeric address value. // We also use this for null pointer. We need the data layout for ConstCastOnly == true - // types to be the same, so all nullables of pointer types use x_ptr - // instead of x_nullable + // types to be the same, so all optionals of pointer types use x_ptr + // instead of x_optional ConstPtrSpecialHardCodedAddr, // This means that the pointer represents memory of assigning to _. // That is, storing discards the data, and loading is invalid. @@ -222,10 +222,10 @@ enum RuntimeHintErrorUnion { RuntimeHintErrorUnionNonError, }; -enum RuntimeHintMaybe { - RuntimeHintMaybeUnknown, - RuntimeHintMaybeNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known. - RuntimeHintMaybeNonNull, +enum RuntimeHintOptional { + RuntimeHintOptionalUnknown, + RuntimeHintOptionalNull, // TODO is this value even possible? if this is the case it might mean the const value is compile time known. + RuntimeHintOptionalNonNull, }; enum RuntimeHintPtr { @@ -254,7 +254,7 @@ struct ConstExprValue { bool x_bool; ConstBoundFnValue x_bound_fn; TypeTableEntry *x_type; - ConstExprValue *x_nullable; + ConstExprValue *x_optional; ConstErrValue x_err_union; ErrorTableEntry *x_err_set; BigInt x_enum_tag; @@ -268,7 +268,7 @@ struct ConstExprValue { // populated if special == ConstValSpecialRuntime RuntimeHintErrorUnion rh_error_union; - RuntimeHintMaybe rh_maybe; + RuntimeHintOptional rh_maybe; RuntimeHintPtr rh_ptr; } data; }; @@ -556,7 +556,7 @@ enum BinOpType { BinOpTypeMultWrap, BinOpTypeDiv, BinOpTypeMod, - BinOpTypeUnwrapMaybe, + BinOpTypeUnwrapOptional, BinOpTypeArrayCat, BinOpTypeArrayMult, BinOpTypeErrorUnion, @@ -623,8 +623,8 @@ enum PrefixOp { PrefixOpBinNot, PrefixOpNegation, PrefixOpNegationWrap, - PrefixOpMaybe, - PrefixOpUnwrapMaybe, + PrefixOpOptional, + PrefixOpUnwrapOptional, PrefixOpAddrOf, }; @@ -1052,7 +1052,7 @@ struct TypeTableEntryStruct { HashMap fields_by_name; }; -struct TypeTableEntryMaybe { +struct TypeTableEntryOptional { TypeTableEntry *child_type; }; @@ -1175,7 +1175,7 @@ enum TypeTableEntryId { TypeTableEntryIdComptimeInt, TypeTableEntryIdUndefined, TypeTableEntryIdNull, - TypeTableEntryIdMaybe, + TypeTableEntryIdOptional, TypeTableEntryIdErrorUnion, TypeTableEntryIdErrorSet, TypeTableEntryIdEnum, @@ -1206,7 +1206,7 @@ struct TypeTableEntry { TypeTableEntryFloat floating; TypeTableEntryArray array; TypeTableEntryStruct structure; - TypeTableEntryMaybe maybe; + TypeTableEntryOptional maybe; TypeTableEntryErrorUnion error_union; TypeTableEntryErrorSet error_set; TypeTableEntryEnum enumeration; @@ -1402,7 +1402,7 @@ enum PanicMsgId { PanicMsgIdRemainderDivisionByZero, PanicMsgIdExactDivisionRemainder, PanicMsgIdSliceWidenRemainder, - PanicMsgIdUnwrapMaybeFail, + PanicMsgIdUnwrapOptionalFail, PanicMsgIdInvalidErrorCode, PanicMsgIdIncorrectAlignment, PanicMsgIdBadUnionField, @@ -2016,8 +2016,8 @@ enum IrInstructionId { IrInstructionIdAsm, IrInstructionIdSizeOf, IrInstructionIdTestNonNull, - IrInstructionIdUnwrapMaybe, - IrInstructionIdMaybeWrap, + IrInstructionIdUnwrapOptional, + IrInstructionIdOptionalWrap, IrInstructionIdUnionTag, IrInstructionIdClz, IrInstructionIdCtz, @@ -2184,7 +2184,7 @@ enum IrUnOp { IrUnOpNegation, IrUnOpNegationWrap, IrUnOpDereference, - IrUnOpMaybe, + IrUnOpOptional, }; struct IrInstructionUnOp { @@ -2487,7 +2487,7 @@ struct IrInstructionTestNonNull { IrInstruction *value; }; -struct IrInstructionUnwrapMaybe { +struct IrInstructionUnwrapOptional { IrInstruction base; IrInstruction *value; @@ -2745,7 +2745,7 @@ struct IrInstructionUnwrapErrPayload { bool safety_check_on; }; -struct IrInstructionMaybeWrap { +struct IrInstructionOptionalWrap { IrInstruction base; IrInstruction *value; @@ -2954,10 +2954,10 @@ struct IrInstructionExport { struct IrInstructionErrorReturnTrace { IrInstruction base; - enum Nullable { + enum Optional { Null, NonNull, - } nullable; + } optional; }; struct IrInstructionErrorUnion { diff --git a/src/analyze.cpp b/src/analyze.cpp index 16b2cb0590..ed261148ea 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -236,7 +236,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdFn: @@ -272,7 +272,7 @@ bool type_has_zero_bits_known(TypeTableEntry *type_entry) { case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdFn: @@ -520,7 +520,7 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { } else { ensure_complete_type(g, child_type); - TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe); + TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdOptional); assert(child_type->type_ref || child_type->zero_bits); assert(child_type->di_type); entry->is_copyable = type_is_copyable(g, child_type); @@ -1361,7 +1361,7 @@ static bool type_allowed_in_packed_struct(TypeTableEntry *type_entry) { return type_entry->data.structure.layout == ContainerLayoutPacked; case TypeTableEntryIdUnion: return type_entry->data.unionation.layout == ContainerLayoutPacked; - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: { TypeTableEntry *child_type = type_entry->data.maybe.child_type; return type_is_codegen_pointer(child_type); @@ -1415,7 +1415,7 @@ static bool type_allowed_in_extern(CodeGen *g, TypeTableEntry *type_entry) { return type_allowed_in_extern(g, type_entry->data.pointer.child_type); case TypeTableEntryIdStruct: return type_entry->data.structure.layout == ContainerLayoutExtern || type_entry->data.structure.layout == ContainerLayoutPacked; - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: { TypeTableEntry *child_type = type_entry->data.maybe.child_type; return child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn; @@ -1538,7 +1538,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c case TypeTableEntryIdPointer: case TypeTableEntryIdArray: case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -1632,7 +1632,7 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c case TypeTableEntryIdPointer: case TypeTableEntryIdArray: case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -2985,8 +2985,8 @@ static void typecheck_panic_fn(CodeGen *g, FnTableEntry *panic_fn) { return wrong_panic_prototype(g, proto_node, fn_type); } - TypeTableEntry *nullable_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g)); - if (fn_type_id->param_info[1].type != nullable_ptr_to_stack_trace_type) { + TypeTableEntry *optional_ptr_to_stack_trace_type = get_maybe_type(g, get_ptr_to_stack_trace_type(g)); + if (fn_type_id->param_info[1].type != optional_ptr_to_stack_trace_type) { return wrong_panic_prototype(g, proto_node, fn_type); } @@ -3368,7 +3368,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt case TypeTableEntryIdPointer: case TypeTableEntryIdArray: case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -3746,7 +3746,7 @@ static bool is_container(TypeTableEntry *type_entry) { case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdFn: @@ -3805,7 +3805,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdFn: @@ -3824,7 +3824,7 @@ TypeTableEntry *get_codegen_ptr_type(TypeTableEntry *type) { if (type->id == TypeTableEntryIdPointer) return type; if (type->id == TypeTableEntryIdFn) return type; if (type->id == TypeTableEntryIdPromise) return type; - if (type->id == TypeTableEntryIdMaybe) { + if (type->id == TypeTableEntryIdOptional) { if (type->data.maybe.child_type->id == TypeTableEntryIdPointer) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == TypeTableEntryIdFn) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == TypeTableEntryIdPromise) return type->data.maybe.child_type; @@ -4331,7 +4331,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { return type_has_bits(type_entry); case TypeTableEntryIdErrorUnion: return type_has_bits(type_entry->data.error_union.payload_type); - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: return type_has_bits(type_entry->data.maybe.child_type) && !type_is_codegen_pointer(type_entry->data.maybe.child_type); case TypeTableEntryIdUnion: @@ -4709,12 +4709,12 @@ static uint32_t hash_const_val(ConstExprValue *const_val) { case TypeTableEntryIdUnion: // TODO better hashing algorithm return 2709806591; - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: if (get_codegen_ptr_type(const_val->type) != nullptr) { return hash_const_val(const_val) * 1992916303; } else { - if (const_val->data.x_nullable) { - return hash_const_val(const_val->data.x_nullable) * 1992916303; + if (const_val->data.x_optional) { + return hash_const_val(const_val->data.x_optional) * 1992916303; } else { return 4016830364; } @@ -4817,12 +4817,12 @@ static bool can_mutate_comptime_var_state(ConstExprValue *value) { } return false; - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: if (get_codegen_ptr_type(value->type) != nullptr) return value->data.x_ptr.mut == ConstPtrMutComptimeVar; - if (value->data.x_nullable == nullptr) + if (value->data.x_optional == nullptr) return false; - return can_mutate_comptime_var_state(value->data.x_nullable); + return can_mutate_comptime_var_state(value->data.x_optional); case TypeTableEntryIdErrorUnion: if (value->data.x_err_union.err != nullptr) @@ -4869,7 +4869,7 @@ static bool return_type_is_cacheable(TypeTableEntry *return_type) { case TypeTableEntryIdUnion: return false; - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: return return_type_is_cacheable(return_type->data.maybe.child_type); case TypeTableEntryIdErrorUnion: @@ -4978,7 +4978,7 @@ bool type_requires_comptime(TypeTableEntry *type_entry) { case TypeTableEntryIdUnion: assert(type_has_zero_bits_known(type_entry)); return type_entry->data.unionation.requires_comptime; - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: return type_requires_comptime(type_entry->data.maybe.child_type); case TypeTableEntryIdErrorUnion: return type_requires_comptime(type_entry->data.error_union.payload_type); @@ -5460,13 +5460,13 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b) { zig_panic("TODO"); case TypeTableEntryIdNull: zig_panic("TODO"); - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: if (get_codegen_ptr_type(a->type) != nullptr) return const_values_equal_ptr(a, b); - if (a->data.x_nullable == nullptr || b->data.x_nullable == nullptr) { - return (a->data.x_nullable == nullptr && b->data.x_nullable == nullptr); + if (a->data.x_optional == nullptr || b->data.x_optional == nullptr) { + return (a->data.x_optional == nullptr && b->data.x_optional == nullptr); } else { - return const_values_equal(a->data.x_nullable, b->data.x_nullable); + return const_values_equal(a->data.x_optional, b->data.x_optional); } case TypeTableEntryIdErrorUnion: zig_panic("TODO"); @@ -5708,12 +5708,12 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { buf_appendf(buf, "undefined"); return; } - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: { if (get_codegen_ptr_type(const_val->type) != nullptr) return render_const_val_ptr(g, buf, const_val, type_entry->data.maybe.child_type); - if (const_val->data.x_nullable) { - render_const_value(g, buf, const_val->data.x_nullable); + if (const_val->data.x_optional) { + render_const_value(g, buf, const_val->data.x_optional); } else { buf_appendf(buf, "null"); } @@ -5819,7 +5819,7 @@ uint32_t type_id_hash(TypeId x) { case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: case TypeTableEntryIdUnion: @@ -5865,7 +5865,7 @@ bool type_id_eql(TypeId a, TypeId b) { case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdPromise: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -5987,7 +5987,7 @@ static const TypeTableEntryId all_type_ids[] = { TypeTableEntryIdComptimeInt, TypeTableEntryIdUndefined, TypeTableEntryIdNull, - TypeTableEntryIdMaybe, + TypeTableEntryIdOptional, TypeTableEntryIdErrorUnion, TypeTableEntryIdErrorSet, TypeTableEntryIdEnum, @@ -6042,7 +6042,7 @@ size_t type_id_index(TypeTableEntry *entry) { return 11; case TypeTableEntryIdNull: return 12; - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: return 13; case TypeTableEntryIdErrorUnion: return 14; @@ -6100,8 +6100,8 @@ const char *type_id_name(TypeTableEntryId id) { return "Undefined"; case TypeTableEntryIdNull: return "Null"; - case TypeTableEntryIdMaybe: - return "Nullable"; + case TypeTableEntryIdOptional: + return "Optional"; case TypeTableEntryIdErrorUnion: return "ErrorUnion"; case TypeTableEntryIdErrorSet: diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 3785cb6ca1..2c8c03b226 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -50,7 +50,7 @@ static const char *bin_op_str(BinOpType bin_op) { case BinOpTypeAssignBitXor: return "^="; case BinOpTypeAssignBitOr: return "|="; case BinOpTypeAssignMergeErrorSets: return "||="; - case BinOpTypeUnwrapMaybe: return "??"; + case BinOpTypeUnwrapOptional: return "??"; case BinOpTypeArrayCat: return "++"; case BinOpTypeArrayMult: return "**"; case BinOpTypeErrorUnion: return "!"; @@ -66,8 +66,8 @@ static const char *prefix_op_str(PrefixOp prefix_op) { case PrefixOpNegationWrap: return "-%"; case PrefixOpBoolNot: return "!"; case PrefixOpBinNot: return "~"; - case PrefixOpMaybe: return "?"; - case PrefixOpUnwrapMaybe: return "??"; + case PrefixOpOptional: return "?"; + case PrefixOpUnwrapOptional: return "??"; case PrefixOpAddrOf: return "&"; } zig_unreachable(); diff --git a/src/codegen.cpp b/src/codegen.cpp index 65b465a519..da08ecfc9e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -865,7 +865,7 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { return buf_create_from_str("exact division produced remainder"); case PanicMsgIdSliceWidenRemainder: return buf_create_from_str("slice widening size mismatch"); - case PanicMsgIdUnwrapMaybeFail: + case PanicMsgIdUnwrapOptionalFail: return buf_create_from_str("attempt to unwrap null"); case PanicMsgIdUnreachable: return buf_create_from_str("reached unreachable code"); @@ -2734,7 +2734,7 @@ static LLVMValueRef ir_render_un_op(CodeGen *g, IrExecutable *executable, IrInst switch (op_id) { case IrUnOpInvalid: - case IrUnOpMaybe: + case IrUnOpOptional: case IrUnOpDereference: zig_unreachable(); case IrUnOpNegation: @@ -3333,7 +3333,7 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru } static LLVMValueRef gen_non_null_bit(CodeGen *g, TypeTableEntry *maybe_type, LLVMValueRef maybe_handle) { - assert(maybe_type->id == TypeTableEntryIdMaybe); + assert(maybe_type->id == TypeTableEntryIdOptional); TypeTableEntry *child_type = maybe_type->data.maybe.child_type; if (child_type->zero_bits) { return maybe_handle; @@ -3355,23 +3355,23 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable } static LLVMValueRef ir_render_unwrap_maybe(CodeGen *g, IrExecutable *executable, - IrInstructionUnwrapMaybe *instruction) + IrInstructionUnwrapOptional *instruction) { TypeTableEntry *ptr_type = instruction->value->value.type; assert(ptr_type->id == TypeTableEntryIdPointer); TypeTableEntry *maybe_type = ptr_type->data.pointer.child_type; - assert(maybe_type->id == TypeTableEntryIdMaybe); + assert(maybe_type->id == TypeTableEntryIdOptional); TypeTableEntry *child_type = maybe_type->data.maybe.child_type; LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->value); LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); - LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeOk"); - LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapMaybeFail"); + LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); + LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); LLVMBuildCondBr(g->builder, non_null_bit, ok_block, fail_block); LLVMPositionBuilderAtEnd(g->builder, fail_block); - gen_safety_crash(g, PanicMsgIdUnwrapMaybeFail); + gen_safety_crash(g, PanicMsgIdUnwrapOptionalFail); LLVMPositionBuilderAtEnd(g->builder, ok_block); } @@ -3593,17 +3593,17 @@ static LLVMValueRef ir_render_align_cast(CodeGen *g, IrExecutable *executable, I } else if (target_type->id == TypeTableEntryIdFn) { align_bytes = target_type->data.fn.fn_type_id.alignment; ptr_val = target_val; - } else if (target_type->id == TypeTableEntryIdMaybe && + } else if (target_type->id == TypeTableEntryIdOptional && target_type->data.maybe.child_type->id == TypeTableEntryIdPointer) { align_bytes = target_type->data.maybe.child_type->data.pointer.alignment; ptr_val = target_val; - } else if (target_type->id == TypeTableEntryIdMaybe && + } else if (target_type->id == TypeTableEntryIdOptional && target_type->data.maybe.child_type->id == TypeTableEntryIdFn) { align_bytes = target_type->data.maybe.child_type->data.fn.fn_type_id.alignment; ptr_val = target_val; - } else if (target_type->id == TypeTableEntryIdMaybe && + } else if (target_type->id == TypeTableEntryIdOptional && target_type->data.maybe.child_type->id == TypeTableEntryIdPromise) { zig_panic("TODO audit this function"); @@ -3705,7 +3705,7 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn success_order, failure_order, instruction->is_weak); TypeTableEntry *maybe_type = instruction->base.value.type; - assert(maybe_type->id == TypeTableEntryIdMaybe); + assert(maybe_type->id == TypeTableEntryIdOptional); TypeTableEntry *child_type = maybe_type->data.maybe.child_type; if (type_is_codegen_pointer(child_type)) { @@ -4115,10 +4115,10 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu } } -static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionMaybeWrap *instruction) { +static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) { TypeTableEntry *wanted_type = instruction->base.value.type; - assert(wanted_type->id == TypeTableEntryIdMaybe); + assert(wanted_type->id == TypeTableEntryIdOptional); TypeTableEntry *child_type = wanted_type->data.maybe.child_type; @@ -4699,8 +4699,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); case IrInstructionIdTestNonNull: return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction); - case IrInstructionIdUnwrapMaybe: - return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapMaybe *)instruction); + case IrInstructionIdUnwrapOptional: + return ir_render_unwrap_maybe(g, executable, (IrInstructionUnwrapOptional *)instruction); case IrInstructionIdClz: return ir_render_clz(g, executable, (IrInstructionClz *)instruction); case IrInstructionIdCtz: @@ -4741,8 +4741,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction); case IrInstructionIdUnwrapErrPayload: return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction); - case IrInstructionIdMaybeWrap: - return ir_render_maybe_wrap(g, executable, (IrInstructionMaybeWrap *)instruction); + case IrInstructionIdOptionalWrap: + return ir_render_maybe_wrap(g, executable, (IrInstructionOptionalWrap *)instruction); case IrInstructionIdErrWrapCode: return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction); case IrInstructionIdErrWrapPayload: @@ -4972,7 +4972,7 @@ static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, Con } case TypeTableEntryIdPointer: case TypeTableEntryIdFn: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdPromise: { LLVMValueRef ptr_val = gen_const_val(g, const_val, ""); @@ -5137,19 +5137,19 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c } else { return LLVMConstNull(LLVMInt1Type()); } - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: { TypeTableEntry *child_type = type_entry->data.maybe.child_type; if (child_type->zero_bits) { - return LLVMConstInt(LLVMInt1Type(), const_val->data.x_nullable ? 1 : 0, false); + return LLVMConstInt(LLVMInt1Type(), const_val->data.x_optional ? 1 : 0, false); } else if (type_is_codegen_pointer(child_type)) { return gen_const_val_ptr(g, const_val, name); } else { LLVMValueRef child_val; LLVMValueRef maybe_val; bool make_unnamed_struct; - if (const_val->data.x_nullable) { - child_val = gen_const_val(g, const_val->data.x_nullable, ""); + if (const_val->data.x_optional) { + child_val = gen_const_val(g, const_val->data.x_optional, ""); maybe_val = LLVMConstAllOnes(LLVMInt1Type()); make_unnamed_struct = is_llvm_value_unnamed_type(const_val->type, child_val); @@ -5755,8 +5755,8 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdSlice) { IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; slot = &slice_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdMaybeWrap) { - IrInstructionMaybeWrap *maybe_wrap_instruction = (IrInstructionMaybeWrap *)instruction; + } else if (instruction->id == IrInstructionIdOptionalWrap) { + IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction; slot = &maybe_wrap_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdErrWrapPayload) { IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction; @@ -6511,7 +6511,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " ComptimeInt: void,\n" " Undefined: void,\n" " Null: void,\n" - " Nullable: Nullable,\n" + " Optional: Optional,\n" " ErrorUnion: ErrorUnion,\n" " ErrorSet: ErrorSet,\n" " Enum: Enum,\n" @@ -6570,7 +6570,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { " defs: []Definition,\n" " };\n" "\n" - " pub const Nullable = struct {\n" + " pub const Optional = struct {\n" " child: type,\n" " };\n" "\n" @@ -7145,7 +7145,7 @@ static void prepend_c_type_to_decl_list(CodeGen *g, GenH *gen_h, TypeTableEntry case TypeTableEntryIdArray: prepend_c_type_to_decl_list(g, gen_h, type_entry->data.array.child_type); return; - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: prepend_c_type_to_decl_list(g, gen_h, type_entry->data.maybe.child_type); return; case TypeTableEntryIdFn: @@ -7234,7 +7234,7 @@ static void get_c_type(CodeGen *g, GenH *gen_h, TypeTableEntry *type_entry, Buf buf_appendf(out_buf, "%s%s *", const_str, buf_ptr(&child_buf)); break; } - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: { TypeTableEntry *child_type = type_entry->data.maybe.child_type; if (child_type->zero_bits) { @@ -7448,7 +7448,7 @@ static void gen_h_file(CodeGen *g) { case TypeTableEntryIdBlock: case TypeTableEntryIdBoundFn: case TypeTableEntryIdArgTuple: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdFn: case TypeTableEntryIdPromise: zig_unreachable(); diff --git a/src/ir.cpp b/src/ir.cpp index 10098f3c32..02606fc4aa 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -47,7 +47,7 @@ enum ConstCastResultId { ConstCastResultIdErrSetGlobal, ConstCastResultIdPointerChild, ConstCastResultIdSliceChild, - ConstCastResultIdNullableChild, + ConstCastResultIdOptionalChild, ConstCastResultIdErrorUnionPayload, ConstCastResultIdErrorUnionErrorSet, ConstCastResultIdFnAlign, @@ -86,7 +86,7 @@ struct ConstCastOnly { ConstCastErrSetMismatch error_set; ConstCastOnly *pointer_child; ConstCastOnly *slice_child; - ConstCastOnly *nullable_child; + ConstCastOnly *optional_child; ConstCastOnly *error_union_payload; ConstCastOnly *error_union_error_set; ConstCastOnly *return_type; @@ -372,8 +372,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTestNonNull *) { return IrInstructionIdTestNonNull; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapMaybe *) { - return IrInstructionIdUnwrapMaybe; +static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapOptional *) { + return IrInstructionIdUnwrapOptional; } static constexpr IrInstructionId ir_instruction_id(IrInstructionClz *) { @@ -524,8 +524,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrPayload return IrInstructionIdUnwrapErrPayload; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionMaybeWrap *) { - return IrInstructionIdMaybeWrap; +static constexpr IrInstructionId ir_instruction_id(IrInstructionOptionalWrap *) { + return IrInstructionIdOptionalWrap; } static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapPayload *) { @@ -1571,7 +1571,7 @@ static IrInstruction *ir_build_test_nonnull_from(IrBuilder *irb, IrInstruction * static IrInstruction *ir_build_unwrap_maybe(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value, bool safety_check_on) { - IrInstructionUnwrapMaybe *instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionUnwrapOptional *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; instruction->safety_check_on = safety_check_on; @@ -1590,7 +1590,7 @@ static IrInstruction *ir_build_unwrap_maybe_from(IrBuilder *irb, IrInstruction * } static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionMaybeWrap *instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionOptionalWrap *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; ir_ref_instruction(value, irb->current_basic_block); @@ -2496,9 +2496,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } -static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) { +static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Optional optional) { IrInstructionErrorReturnTrace *instruction = ir_build_instruction(irb, scope, source_node); - instruction->nullable = nullable; + instruction->optional = optional; return &instruction->base; } @@ -3295,9 +3295,9 @@ static IrInstruction *ir_gen_maybe_ok_or(IrBuilder *irb, Scope *parent_scope, As is_comptime = ir_build_test_comptime(irb, parent_scope, node, is_non_null); } - IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "MaybeNonNull"); - IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "MaybeNull"); - IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "MaybeEnd"); + IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "OptionalNonNull"); + IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OptionalNull"); + IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd"); ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, null_block); @@ -3426,7 +3426,7 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult); case BinOpTypeMergeErrorSets: return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); - case BinOpTypeUnwrapMaybe: + case BinOpTypeUnwrapOptional: return ir_gen_maybe_ok_or(irb, scope, node); case BinOpTypeErrorUnion: return ir_gen_error_union(irb, scope, node); @@ -4703,9 +4703,9 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval); case PrefixOpNegationWrap: return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval); - case PrefixOpMaybe: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpMaybe), lval); - case PrefixOpUnwrapMaybe: + case PrefixOpOptional: + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval); + case PrefixOpUnwrapOptional: return ir_gen_maybe_assert_ok(irb, scope, node, lval); case PrefixOpAddrOf: { AstNode *expr_node = node->data.prefix_op_expr.primary_expr; @@ -5370,9 +5370,9 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node, maybe_val_ptr); IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_val); - IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "MaybeThen"); - IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "MaybeElse"); - IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "MaybeEndIf"); + IrBasicBlock *then_block = ir_create_basic_block(irb, scope, "OptionalThen"); + IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "OptionalElse"); + IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "OptionalEndIf"); IrInstruction *is_comptime; if (ir_should_inline(irb->exec, scope)) { @@ -7519,7 +7519,7 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc } } else if (const_val_fits_in_num_lit(const_val, other_type)) { return true; - } else if (other_type->id == TypeTableEntryIdMaybe) { + } else if (other_type->id == TypeTableEntryIdOptional) { TypeTableEntry *child_type = other_type->data.maybe.child_type; if (const_val_fits_in_num_lit(const_val, child_type)) { return true; @@ -7663,7 +7663,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry return result; // * and [*] can do a const-cast-only to ?* and ?[*], respectively - if (expected_type->id == TypeTableEntryIdMaybe && + if (expected_type->id == TypeTableEntryIdOptional && expected_type->data.maybe.child_type->id == TypeTableEntryIdPointer && actual_type->id == TypeTableEntryIdPointer) { @@ -7718,12 +7718,12 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, TypeTableEntry } // maybe - if (expected_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdMaybe) { + if (expected_type->id == TypeTableEntryIdOptional && actual_type->id == TypeTableEntryIdOptional) { ConstCastOnly child = types_match_const_cast_only(ira, expected_type->data.maybe.child_type, actual_type->data.maybe.child_type, source_node); if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdNullableChild; - result.data.nullable_child = allocate_nonzero(1); - *result.data.nullable_child = child; + result.id = ConstCastResultIdOptionalChild; + result.data.optional_child = allocate_nonzero(1); + *result.data.optional_child = child; } return result; } @@ -7925,7 +7925,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, } // implicit conversion from ?T to ?U - if (expected_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdMaybe) { + if (expected_type->id == TypeTableEntryIdOptional && actual_type->id == TypeTableEntryIdOptional) { ImplicitCastMatchResult res = ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type, actual_type->data.maybe.child_type, value); if (res != ImplicitCastMatchResultNo) @@ -7933,7 +7933,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, } // implicit conversion from non maybe type to maybe type - if (expected_type->id == TypeTableEntryIdMaybe) { + if (expected_type->id == TypeTableEntryIdOptional) { ImplicitCastMatchResult res = ir_types_match_with_implicit_cast(ira, expected_type->data.maybe.child_type, actual_type, value); if (res != ImplicitCastMatchResultNo) @@ -7941,7 +7941,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, } // implicit conversion from null literal to maybe type - if (expected_type->id == TypeTableEntryIdMaybe && + if (expected_type->id == TypeTableEntryIdOptional && actual_type->id == TypeTableEntryIdNull) { return ImplicitCastMatchResultYes; @@ -7963,7 +7963,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, // implicit conversion from T to U!?T if (expected_type->id == TypeTableEntryIdErrorUnion && - expected_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe && + expected_type->data.error_union.payload_type->id == TypeTableEntryIdOptional && ir_types_match_with_implicit_cast(ira, expected_type->data.error_union.payload_type->data.maybe.child_type, actual_type, value)) @@ -8072,7 +8072,7 @@ static ImplicitCastMatchResult ir_types_match_with_implicit_cast(IrAnalyze *ira, } // implicit [N]T to ?[]const T - if (expected_type->id == TypeTableEntryIdMaybe && + if (expected_type->id == TypeTableEntryIdOptional && is_slice(expected_type->data.maybe.child_type) && actual_type->id == TypeTableEntryIdArray) { @@ -8552,13 +8552,13 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod continue; } - if (prev_type->id == TypeTableEntryIdMaybe && + if (prev_type->id == TypeTableEntryIdOptional && types_match_const_cast_only(ira, prev_type->data.maybe.child_type, cur_type, source_node).id == ConstCastResultIdOk) { continue; } - if (cur_type->id == TypeTableEntryIdMaybe && + if (cur_type->id == TypeTableEntryIdOptional && types_match_const_cast_only(ira, cur_type->data.maybe.child_type, prev_type, source_node).id == ConstCastResultIdOk) { prev_inst = cur_inst; @@ -8711,7 +8711,7 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod ir_add_error_node(ira, source_node, buf_sprintf("unable to make maybe out of number literal")); return ira->codegen->builtin_types.entry_invalid; - } else if (prev_inst->value.type->id == TypeTableEntryIdMaybe) { + } else if (prev_inst->value.type->id == TypeTableEntryIdOptional) { return prev_inst->value.type; } else { return get_maybe_type(ira->codegen, prev_inst->value.type); @@ -9193,7 +9193,7 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { } static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { - assert(wanted_type->id == TypeTableEntryIdMaybe); + assert(wanted_type->id == TypeTableEntryIdOptional); if (instr_is_comptime(value)) { TypeTableEntry *payload_type = wanted_type->data.maybe.child_type; @@ -9211,7 +9211,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc if (get_codegen_ptr_type(wanted_type) != nullptr) { copy_const_val(&const_instruction->base.value, val, val->data.x_ptr.mut == ConstPtrMutComptimeConst); } else { - const_instruction->base.value.data.x_nullable = val; + const_instruction->base.value.data.x_optional = val; } const_instruction->base.value.type = wanted_type; return &const_instruction->base; @@ -9219,7 +9219,7 @@ static IrInstruction *ir_analyze_maybe_wrap(IrAnalyze *ira, IrInstruction *sourc IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value); result->value.type = wanted_type; - result->value.data.rh_maybe = RuntimeHintMaybeNonNull; + result->value.data.rh_maybe = RuntimeHintOptionalNonNull; ir_add_alloca(ira, result, wanted_type); return result; } @@ -9361,7 +9361,7 @@ static IrInstruction *ir_analyze_cast_ref(IrAnalyze *ira, IrInstruction *source_ } static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, TypeTableEntry *wanted_type) { - assert(wanted_type->id == TypeTableEntryIdMaybe); + assert(wanted_type->id == TypeTableEntryIdOptional); assert(instr_is_comptime(value)); ConstExprValue *val = ir_resolve_const(ira, value, UndefBad); @@ -9373,7 +9373,7 @@ static IrInstruction *ir_analyze_null_to_maybe(IrAnalyze *ira, IrInstruction *so const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; const_instruction->base.value.data.x_ptr.data.hard_coded_addr.addr = 0; } else { - const_instruction->base.value.data.x_nullable = nullptr; + const_instruction->base.value.data.x_optional = nullptr; } const_instruction->base.value.type = wanted_type; return &const_instruction->base; @@ -9992,7 +9992,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } // explicit cast from [N]T to ?[]const N - if (wanted_type->id == TypeTableEntryIdMaybe && + if (wanted_type->id == TypeTableEntryIdOptional && is_slice(wanted_type->data.maybe.child_type) && actual_type->id == TypeTableEntryIdArray) { @@ -10091,7 +10091,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from T to ?T // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism - if (wanted_type->id == TypeTableEntryIdMaybe) { + if (wanted_type->id == TypeTableEntryIdOptional) { TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type; if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk) { return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type); @@ -10120,7 +10120,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } // explicit cast from null literal to maybe type - if (wanted_type->id == TypeTableEntryIdMaybe && + if (wanted_type->id == TypeTableEntryIdOptional && actual_type->id == TypeTableEntryIdNull) { return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type); @@ -10173,8 +10173,8 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from T to E!?T if (wanted_type->id == TypeTableEntryIdErrorUnion && - wanted_type->data.error_union.payload_type->id == TypeTableEntryIdMaybe && - actual_type->id != TypeTableEntryIdMaybe) + wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional && + actual_type->id != TypeTableEntryIdOptional) { TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type; if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node).id == ConstCastResultIdOk || @@ -10737,13 +10737,13 @@ static bool resolve_cmp_op_id(IrBinOp op_id, Cmp cmp) { } } -static bool nullable_value_is_null(ConstExprValue *val) { +static bool optional_value_is_null(ConstExprValue *val) { assert(val->special == ConstValSpecialStatic); if (get_codegen_ptr_type(val->type) != nullptr) { return val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && val->data.x_ptr.data.hard_coded_addr.addr == 0; } else { - return val->data.x_nullable == nullptr; + return val->data.x_optional == nullptr; } } @@ -10755,8 +10755,8 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp IrBinOp op_id = bin_op_instruction->op_id; bool is_equality_cmp = (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq); if (is_equality_cmp && - ((op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdMaybe) || - (op2->value.type->id == TypeTableEntryIdNull && op1->value.type->id == TypeTableEntryIdMaybe) || + ((op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdOptional) || + (op2->value.type->id == TypeTableEntryIdNull && op1->value.type->id == TypeTableEntryIdOptional) || (op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdNull))) { if (op1->value.type->id == TypeTableEntryIdNull && op2->value.type->id == TypeTableEntryIdNull) { @@ -10776,7 +10776,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp ConstExprValue *maybe_val = ir_resolve_const(ira, maybe_op, UndefBad); if (!maybe_val) return ira->codegen->builtin_types.entry_invalid; - bool is_null = nullable_value_is_null(maybe_val); + bool is_null = optional_value_is_null(maybe_val); ConstExprValue *out_val = ir_build_const_from(ira, &bin_op_instruction->base); out_val->data.x_bool = (op_id == IrBinOpCmpEq) ? is_null : !is_null; return ira->codegen->builtin_types.entry_bool; @@ -10925,7 +10925,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp case TypeTableEntryIdStruct: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdUnion: ir_add_error_node(ira, source_node, @@ -11998,7 +11998,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdNamespace: @@ -12022,7 +12022,7 @@ static TypeTableEntry *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructi case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: zig_panic("TODO export const value of type %s", buf_ptr(&target->value.type->name)); @@ -12049,24 +12049,24 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) { static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, IrInstructionErrorReturnTrace *instruction) { - if (instruction->nullable == IrInstructionErrorReturnTrace::Null) { + if (instruction->optional == IrInstructionErrorReturnTrace::Null) { TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen); - TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); + TypeTableEntry *optional_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type); if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) { ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - assert(get_codegen_ptr_type(nullable_type) != nullptr); + assert(get_codegen_ptr_type(optional_type) != nullptr); out_val->data.x_ptr.special = ConstPtrSpecialHardCodedAddr; out_val->data.x_ptr.data.hard_coded_addr.addr = 0; - return nullable_type; + return optional_type; } IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, instruction->nullable); + instruction->base.source_node, instruction->optional); ir_link_new_instruction(new_instruction, &instruction->base); - return nullable_type; + return optional_type; } else { assert(ira->codegen->have_err_ret_tracing); IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, instruction->nullable); + instruction->base.source_node, instruction->optional); ir_link_new_instruction(new_instruction, &instruction->base); return get_ptr_to_stack_trace_type(ira->codegen); } @@ -12998,7 +12998,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -13017,7 +13017,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op case TypeTableEntryIdUnreachable: case TypeTableEntryIdOpaque: ir_add_error_node(ira, un_op_instruction->base.source_node, - buf_sprintf("type '%s' not nullable", buf_ptr(&type_entry->name))); + buf_sprintf("type '%s' not optional", buf_ptr(&type_entry->name))); return ira->codegen->builtin_types.entry_invalid; } zig_unreachable(); @@ -13109,7 +13109,7 @@ static TypeTableEntry *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstructio return ir_analyze_negation(ira, un_op_instruction); case IrUnOpDereference: return ir_analyze_dereference(ira, un_op_instruction); - case IrUnOpMaybe: + case IrUnOpOptional: return ir_analyze_maybe(ira, un_op_instruction); } zig_unreachable(); @@ -14155,7 +14155,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru buf_ptr(&child_type->name), buf_ptr(field_name))); return ira->codegen->builtin_types.entry_invalid; } - } else if (child_type->id == TypeTableEntryIdMaybe) { + } else if (child_type->id == TypeTableEntryIdOptional) { if (buf_eql_str(field_name, "Child")) { bool ptr_is_const = true; bool ptr_is_volatile = false; @@ -14339,7 +14339,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi case TypeTableEntryIdPointer: case TypeTableEntryIdArray: case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -14607,7 +14607,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, case TypeTableEntryIdStruct: case TypeTableEntryIdComptimeFloat: case TypeTableEntryIdComptimeInt: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -14715,7 +14715,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, case TypeTableEntryIdStruct: case TypeTableEntryIdComptimeFloat: case TypeTableEntryIdComptimeInt: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -14786,7 +14786,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, case TypeTableEntryIdPointer: case TypeTableEntryIdArray: case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -14810,14 +14810,14 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn TypeTableEntry *type_entry = value->value.type; - if (type_entry->id == TypeTableEntryIdMaybe) { + if (type_entry->id == TypeTableEntryIdOptional) { if (instr_is_comptime(value)) { ConstExprValue *maybe_val = ir_resolve_const(ira, value, UndefBad); if (!maybe_val) return ira->codegen->builtin_types.entry_invalid; ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base); - out_val->data.x_bool = !nullable_value_is_null(maybe_val); + out_val->data.x_bool = !optional_value_is_null(maybe_val); return ira->codegen->builtin_types.entry_bool; } @@ -14835,7 +14835,7 @@ static TypeTableEntry *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIn } static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, - IrInstructionUnwrapMaybe *unwrap_maybe_instruction) + IrInstructionUnwrapOptional *unwrap_maybe_instruction) { IrInstruction *value = unwrap_maybe_instruction->value->other; if (type_is_invalid(value->value.type)) @@ -14863,9 +14863,9 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile); ir_link_new_instruction(result_instr, &unwrap_maybe_instruction->base); return result_instr->value.type; - } else if (type_entry->id != TypeTableEntryIdMaybe) { + } else if (type_entry->id != TypeTableEntryIdOptional) { ir_add_error_node(ira, unwrap_maybe_instruction->value->source_node, - buf_sprintf("expected nullable type, found '%s'", buf_ptr(&type_entry->name))); + buf_sprintf("expected optional type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->builtin_types.entry_invalid; } TypeTableEntry *child_type = type_entry->data.maybe.child_type; @@ -14881,7 +14881,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, ConstExprValue *maybe_val = const_ptr_pointee(ira->codegen, val); if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - if (nullable_value_is_null(maybe_val)) { + if (optional_value_is_null(maybe_val)) { ir_add_error(ira, &unwrap_maybe_instruction->base, buf_sprintf("unable to unwrap null")); return ira->codegen->builtin_types.entry_invalid; } @@ -14891,7 +14891,7 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_maybe(IrAnalyze *ira, if (type_is_codegen_pointer(child_type)) { out_val->data.x_ptr.data.ref.pointee = maybe_val; } else { - out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_nullable; + out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional; } return result_type; } @@ -15216,7 +15216,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, case TypeTableEntryIdStruct: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdBlock: case TypeTableEntryIdBoundFn: case TypeTableEntryIdArgTuple: @@ -15737,7 +15737,7 @@ static TypeTableEntry *ir_analyze_min_max(IrAnalyze *ira, IrInstruction *source_ case TypeTableEntryIdComptimeInt: case TypeTableEntryIdUndefined: case TypeTableEntryIdNull: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdUnion: @@ -16255,11 +16255,11 @@ static bool ir_make_type_info_defs(IrAnalyze *ira, ConstExprValue *out_val, Scop 0, 0); fn_def_fields[6].type = get_maybe_type(ira->codegen, get_slice_type(ira->codegen, u8_ptr)); if (fn_node->is_extern && buf_len(fn_node->lib_name) > 0) { - fn_def_fields[6].data.x_nullable = create_const_vals(1); + fn_def_fields[6].data.x_optional = create_const_vals(1); ConstExprValue *lib_name = create_const_str_lit(ira->codegen, fn_node->lib_name); - init_const_slice(ira->codegen, fn_def_fields[6].data.x_nullable, lib_name, 0, buf_len(fn_node->lib_name), true); + init_const_slice(ira->codegen, fn_def_fields[6].data.x_optional, lib_name, 0, buf_len(fn_node->lib_name), true); } else { - fn_def_fields[6].data.x_nullable = nullptr; + fn_def_fields[6].data.x_optional = nullptr; } // return_type: type ensure_field_index(fn_def_val->type, "return_type", 7); @@ -16507,11 +16507,11 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t break; } - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: { result = create_const_vals(1); result->special = ConstValSpecialStatic; - result->type = ir_type_info_get_type(ira, "Nullable"); + result->type = ir_type_info_get_type(ira, "Optional"); ConstExprValue *fields = create_const_vals(1); result->data.x_struct.fields = fields; @@ -16725,10 +16725,10 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t inner_fields[1].type = get_maybe_type(ira->codegen, type_info_enum_field_type); if (fields[1].data.x_type == ira->codegen->builtin_types.entry_undef) { - inner_fields[1].data.x_nullable = nullptr; + inner_fields[1].data.x_optional = nullptr; } else { - inner_fields[1].data.x_nullable = create_const_vals(1); - make_enum_field_val(inner_fields[1].data.x_nullable, union_field->enum_field, type_info_enum_field_type); + inner_fields[1].data.x_optional = create_const_vals(1); + make_enum_field_val(inner_fields[1].data.x_optional, union_field->enum_field, type_info_enum_field_type); } inner_fields[2].special = ConstValSpecialStatic; @@ -16796,13 +16796,13 @@ static ConstExprValue *ir_make_type_info_value(IrAnalyze *ira, TypeTableEntry *t inner_fields[1].type = get_maybe_type(ira->codegen, ira->codegen->builtin_types.entry_usize); if (!type_has_bits(struct_field->type_entry)) { - inner_fields[1].data.x_nullable = nullptr; + inner_fields[1].data.x_optional = nullptr; } else { size_t byte_offset = LLVMOffsetOfElement(ira->codegen->target_data_ref, type_entry->type_ref, struct_field->gen_index); - inner_fields[1].data.x_nullable = create_const_vals(1); - inner_fields[1].data.x_nullable->special = ConstValSpecialStatic; - inner_fields[1].data.x_nullable->type = ira->codegen->builtin_types.entry_usize; - bigint_init_unsigned(&inner_fields[1].data.x_nullable->data.x_bigint, byte_offset); + inner_fields[1].data.x_optional = create_const_vals(1); + inner_fields[1].data.x_optional->special = ConstValSpecialStatic; + inner_fields[1].data.x_optional->type = ira->codegen->builtin_types.entry_usize; + bigint_init_unsigned(&inner_fields[1].data.x_optional->data.x_bigint, byte_offset); } inner_fields[2].special = ConstValSpecialStatic; @@ -18027,7 +18027,7 @@ static TypeTableEntry *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstruc case TypeTableEntryIdPromise: case TypeTableEntryIdArray: case TypeTableEntryIdStruct: - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: case TypeTableEntryIdErrorUnion: case TypeTableEntryIdErrorSet: case TypeTableEntryIdEnum: @@ -18591,7 +18591,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 old_align_bytes = fn_type_id.alignment; fn_type_id.alignment = align_bytes; result_type = get_fn_type(ira->codegen, &fn_type_id); - } else if (target_type->id == TypeTableEntryIdMaybe && + } else if (target_type->id == TypeTableEntryIdOptional && target_type->data.maybe.child_type->id == TypeTableEntryIdPointer) { TypeTableEntry *ptr_type = target_type->data.maybe.child_type; @@ -18599,7 +18599,7 @@ static IrInstruction *ir_align_cast(IrAnalyze *ira, IrInstruction *target, uint3 TypeTableEntry *better_ptr_type = adjust_ptr_align(ira->codegen, ptr_type, align_bytes); result_type = get_maybe_type(ira->codegen, better_ptr_type); - } else if (target_type->id == TypeTableEntryIdMaybe && + } else if (target_type->id == TypeTableEntryIdOptional && target_type->data.maybe.child_type->id == TypeTableEntryIdFn) { FnTypeId fn_type_id = target_type->data.maybe.child_type->data.fn.fn_type_id; @@ -18757,7 +18757,7 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue return; case TypeTableEntryIdStruct: zig_panic("TODO buf_write_value_bytes struct type"); - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: zig_panic("TODO buf_write_value_bytes maybe type"); case TypeTableEntryIdErrorUnion: zig_panic("TODO buf_write_value_bytes error union"); @@ -18815,7 +18815,7 @@ static void buf_read_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue zig_panic("TODO buf_read_value_bytes array type"); case TypeTableEntryIdStruct: zig_panic("TODO buf_read_value_bytes struct type"); - case TypeTableEntryIdMaybe: + case TypeTableEntryIdOptional: zig_panic("TODO buf_read_value_bytes maybe type"); case TypeTableEntryIdErrorUnion: zig_panic("TODO buf_read_value_bytes error union"); @@ -19731,7 +19731,7 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi case IrInstructionIdUnionInit: case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: - case IrInstructionIdMaybeWrap: + case IrInstructionIdOptionalWrap: case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: case IrInstructionIdCast: @@ -19791,8 +19791,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_size_of(ira, (IrInstructionSizeOf *)instruction); case IrInstructionIdTestNonNull: return ir_analyze_instruction_test_non_null(ira, (IrInstructionTestNonNull *)instruction); - case IrInstructionIdUnwrapMaybe: - return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapMaybe *)instruction); + case IrInstructionIdUnwrapOptional: + return ir_analyze_instruction_unwrap_maybe(ira, (IrInstructionUnwrapOptional *)instruction); case IrInstructionIdClz: return ir_analyze_instruction_clz(ira, (IrInstructionClz *)instruction); case IrInstructionIdCtz: @@ -20128,7 +20128,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdSliceType: case IrInstructionIdSizeOf: case IrInstructionIdTestNonNull: - case IrInstructionIdUnwrapMaybe: + case IrInstructionIdUnwrapOptional: case IrInstructionIdClz: case IrInstructionIdCtz: case IrInstructionIdSwitchVar: @@ -20150,7 +20150,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFrameAddress: case IrInstructionIdTestErr: case IrInstructionIdUnwrapErrCode: - case IrInstructionIdMaybeWrap: + case IrInstructionIdOptionalWrap: case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: case IrInstructionIdFnProto: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 776ef64566..43907fa9d4 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -148,7 +148,7 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { return "-%"; case IrUnOpDereference: return "*"; - case IrUnOpMaybe: + case IrUnOpOptional: return "?"; } zig_unreachable(); @@ -481,7 +481,7 @@ static void ir_print_test_null(IrPrint *irp, IrInstructionTestNonNull *instructi fprintf(irp->f, " != null"); } -static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapMaybe *instruction) { +static void ir_print_unwrap_maybe(IrPrint *irp, IrInstructionUnwrapOptional *instruction) { fprintf(irp->f, "&??*"); ir_print_other_instruction(irp, instruction->value); if (!instruction->safety_check_on) { @@ -777,7 +777,7 @@ static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayl } } -static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionMaybeWrap *instruction) { +static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) { fprintf(irp->f, "@maybeWrap("); ir_print_other_instruction(irp, instruction->value); fprintf(irp->f, ")"); @@ -1032,7 +1032,7 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) { static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) { fprintf(irp->f, "@errorReturnTrace("); - switch (instruction->nullable) { + switch (instruction->optional) { case IrInstructionErrorReturnTrace::Null: fprintf(irp->f, "Null"); break; @@ -1348,8 +1348,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTestNonNull: ir_print_test_null(irp, (IrInstructionTestNonNull *)instruction); break; - case IrInstructionIdUnwrapMaybe: - ir_print_unwrap_maybe(irp, (IrInstructionUnwrapMaybe *)instruction); + case IrInstructionIdUnwrapOptional: + ir_print_unwrap_maybe(irp, (IrInstructionUnwrapOptional *)instruction); break; case IrInstructionIdCtz: ir_print_ctz(irp, (IrInstructionCtz *)instruction); @@ -1465,8 +1465,8 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdUnwrapErrPayload: ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction); break; - case IrInstructionIdMaybeWrap: - ir_print_maybe_wrap(irp, (IrInstructionMaybeWrap *)instruction); + case IrInstructionIdOptionalWrap: + ir_print_maybe_wrap(irp, (IrInstructionOptionalWrap *)instruction); break; case IrInstructionIdErrWrapCode: ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction); diff --git a/src/parser.cpp b/src/parser.cpp index 3ad2de906b..2ee69f81ab 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1046,12 +1046,11 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index } /* -SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | PtrDerefExpression | SliceExpression) +SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ".*" | ".?") FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen) ArrayAccessExpression : token(LBracket) Expression token(RBracket) SliceExpression = "[" Expression ".." option(Expression) "]" FieldAccessExpression : token(Dot) token(Symbol) -PtrDerefExpression = ".*" StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression */ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) { @@ -1148,6 +1147,14 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token); node->data.ptr_deref_expr.target = primary_expr; + primary_expr = node; + } else if (token->id == TokenIdQuestion) { + *token_index += 1; + + AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, first_token); + node->data.prefix_op_expr.prefix_op = PrefixOpUnwrapOptional; + node->data.prefix_op_expr.primary_expr = primary_expr; + primary_expr = node; } else { ast_invalid_token_error(pc, token); @@ -1165,8 +1172,8 @@ static PrefixOp tok_to_prefix_op(Token *token) { case TokenIdDash: return PrefixOpNegation; case TokenIdMinusPercent: return PrefixOpNegationWrap; case TokenIdTilde: return PrefixOpBinNot; - case TokenIdMaybe: return PrefixOpMaybe; - case TokenIdDoubleQuestion: return PrefixOpUnwrapMaybe; + case TokenIdQuestion: return PrefixOpOptional; + case TokenIdDoubleQuestion: return PrefixOpUnwrapOptional; case TokenIdAmpersand: return PrefixOpAddrOf; default: return PrefixOpInvalid; } @@ -2304,8 +2311,8 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, size_t *token_index, bool ma } /* -UnwrapExpression : BoolOrExpression (UnwrapMaybe | UnwrapError) | BoolOrExpression -UnwrapMaybe : "??" BoolOrExpression +UnwrapExpression : BoolOrExpression (UnwrapOptional | UnwrapError) | BoolOrExpression +UnwrapOptional : "??" BoolOrExpression UnwrapError = "catch" option("|" Symbol "|") Expression */ static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, bool mandatory) { @@ -2322,7 +2329,7 @@ static AstNode *ast_parse_unwrap_expr(ParseContext *pc, size_t *token_index, boo AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); node->data.bin_op_expr.op1 = lhs; - node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe; + node->data.bin_op_expr.bin_op = BinOpTypeUnwrapOptional; node->data.bin_op_expr.op2 = rhs; return node; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index badbd695ec..cfabdf11ad 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -625,7 +625,7 @@ void tokenize(Buf *buf, Tokenization *out) { t.state = TokenizeStateSawDot; break; case '?': - begin_token(&t, TokenIdMaybe); + begin_token(&t, TokenIdQuestion); t.state = TokenizeStateSawQuestionMark; break; default: @@ -639,11 +639,6 @@ void tokenize(Buf *buf, Tokenization *out) { end_token(&t); t.state = TokenizeStateStart; break; - case '=': - set_token_id(&t, t.cur_tok, TokenIdMaybeAssign); - end_token(&t); - t.state = TokenizeStateStart; - break; default: t.pos -= 1; end_token(&t); @@ -1609,8 +1604,7 @@ const char * token_name(TokenId id) { case TokenIdLBrace: return "{"; case TokenIdLBracket: return "["; case TokenIdLParen: return "("; - case TokenIdMaybe: return "?"; - case TokenIdMaybeAssign: return "?="; + case TokenIdQuestion: return "?"; case TokenIdMinusEq: return "-="; case TokenIdMinusPercent: return "-%"; case TokenIdMinusPercentEq: return "-%="; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index d0089909cd..7c617f85c6 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -100,8 +100,7 @@ enum TokenId { TokenIdLBrace, TokenIdLBracket, TokenIdLParen, - TokenIdMaybe, - TokenIdMaybeAssign, + TokenIdQuestion, TokenIdMinusEq, TokenIdMinusPercent, TokenIdMinusPercentEq, diff --git a/src/translate_c.cpp b/src/translate_c.cpp index d78bd1fa70..aaaf5a1edb 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -382,7 +382,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r fn_def->data.fn_def.fn_proto = fn_proto; fn_proto->data.fn_proto.fn_def_node = fn_def; - AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, ref_node); + AstNode *unwrap_node = trans_create_node_prefix_op(c, PrefixOpUnwrapOptional, ref_node); AstNode *fn_call_node = trans_create_node(c, NodeTypeFnCallExpr); fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; @@ -410,7 +410,7 @@ static AstNode *trans_create_node_inline_fn(Context *c, Buf *fn_name, AstNode *r } static AstNode *trans_create_node_unwrap_null(Context *c, AstNode *child) { - return trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, child); + return trans_create_node_prefix_op(c, PrefixOpUnwrapOptional, child); } static AstNode *get_global(Context *c, Buf *name) { @@ -879,14 +879,14 @@ static AstNode *trans_type(Context *c, const Type *ty, const SourceLocation &sou } if (qual_type_child_is_fn_proto(child_qt)) { - return trans_create_node_prefix_op(c, PrefixOpMaybe, child_node); + return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); } PtrLen ptr_len = type_is_opaque(c, child_qt.getTypePtr(), source_loc) ? PtrLenSingle : PtrLenUnknown; AstNode *pointer_node = trans_create_node_ptr_type(c, child_qt.isConstQualified(), child_qt.isVolatileQualified(), child_node, ptr_len); - return trans_create_node_prefix_op(c, PrefixOpMaybe, pointer_node); + return trans_create_node_prefix_op(c, PrefixOpOptional, pointer_node); } case Type::Typedef: { @@ -1963,7 +1963,7 @@ static AstNode *trans_unary_operator(Context *c, ResultUsed result_used, TransSc bool is_fn_ptr = qual_type_is_fn_ptr(stmt->getSubExpr()->getType()); if (is_fn_ptr) return value_node; - AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, value_node); + AstNode *unwrapped = trans_create_node_prefix_op(c, PrefixOpUnwrapOptional, value_node); return trans_create_node_ptr_deref(c, unwrapped); } case UO_Plus: @@ -2587,7 +2587,7 @@ static AstNode *trans_call_expr(Context *c, ResultUsed result_used, TransScope * } } if (callee_node == nullptr) { - callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapMaybe, callee_raw_node); + callee_node = trans_create_node_prefix_op(c, PrefixOpUnwrapOptional, callee_raw_node); } } else { callee_node = callee_raw_node; @@ -4301,7 +4301,7 @@ static AstNode *trans_lookup_ast_maybe_fn(Context *c, AstNode *ref_node) { return nullptr; if (prefix_node->type != NodeTypePrefixOpExpr) return nullptr; - if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpMaybe) + if (prefix_node->data.prefix_op_expr.prefix_op != PrefixOpOptional) return nullptr; AstNode *fn_proto_node = prefix_node->data.prefix_op_expr.primary_expr; diff --git a/std/array_list.zig b/std/array_list.zig index 30715f4d6f..1a235d28a3 100644 --- a/std/array_list.zig +++ b/std/array_list.zig @@ -258,7 +258,7 @@ test "iterator ArrayList test" { } it.reset(); - assert(??it.next() == 1); + assert(it.next().? == 1); } test "insert ArrayList test" { diff --git a/std/buf_map.zig b/std/buf_map.zig index 22d821ae7b..0d4f3a6d5e 100644 --- a/std/buf_map.zig +++ b/std/buf_map.zig @@ -72,15 +72,15 @@ test "BufMap" { defer bufmap.deinit(); try bufmap.set("x", "1"); - assert(mem.eql(u8, ??bufmap.get("x"), "1")); + assert(mem.eql(u8, bufmap.get("x").?, "1")); assert(1 == bufmap.count()); try bufmap.set("x", "2"); - assert(mem.eql(u8, ??bufmap.get("x"), "2")); + assert(mem.eql(u8, bufmap.get("x").?, "2")); assert(1 == bufmap.count()); try bufmap.set("x", "3"); - assert(mem.eql(u8, ??bufmap.get("x"), "3")); + assert(mem.eql(u8, bufmap.get("x").?, "3")); assert(1 == bufmap.count()); bufmap.delete("x"); diff --git a/std/event.zig b/std/event.zig index 89ab816bb6..0821c789b7 100644 --- a/std/event.zig +++ b/std/event.zig @@ -40,9 +40,9 @@ pub const TcpServer = struct { self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd)); self.accept_coro = try async TcpServer.handler(self); - errdefer cancel ??self.accept_coro; + errdefer cancel self.accept_coro.?; - try self.loop.addFd(self.sockfd, ??self.accept_coro); + try self.loop.addFd(self.sockfd, self.accept_coro.?); errdefer self.loop.removeFd(self.sockfd); } diff --git a/std/fmt/index.zig b/std/fmt/index.zig index 3844fbb10a..b52625e26e 100644 --- a/std/fmt/index.zig +++ b/std/fmt/index.zig @@ -111,7 +111,7 @@ pub fn formatType( builtin.TypeId.Bool => { return output(context, if (value) "true" else "false"); }, - builtin.TypeId.Nullable => { + builtin.TypeId.Optional => { if (value) |payload| { return formatType(payload, fmt, context, Errors, output); } else { @@ -819,11 +819,11 @@ test "parse unsigned comptime" { test "fmt.format" { { const value: ?i32 = 1234; - try testFmt("nullable: 1234\n", "nullable: {}\n", value); + try testFmt("optional: 1234\n", "optional: {}\n", value); } { const value: ?i32 = null; - try testFmt("nullable: null\n", "nullable: {}\n", value); + try testFmt("optional: null\n", "optional: {}\n", value); } { const value: error!i32 = 1234; diff --git a/std/hash_map.zig b/std/hash_map.zig index a323cdc197..3bd03d4f28 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -265,11 +265,11 @@ test "basic hash map usage" { assert((map.put(4, 44) catch unreachable) == null); assert((map.put(5, 55) catch unreachable) == null); - assert(??(map.put(5, 66) catch unreachable) == 55); - assert(??(map.put(5, 55) catch unreachable) == 66); + assert((map.put(5, 66) catch unreachable).? == 55); + assert((map.put(5, 55) catch unreachable).? == 66); assert(map.contains(2)); - assert((??map.get(2)).value == 22); + assert(map.get(2).?.value == 22); _ = map.remove(2); assert(map.remove(2) == null); assert(map.get(2) == null); @@ -317,7 +317,7 @@ test "iterator hash map" { } it.reset(); - var entry = ??it.next(); + var entry = it.next().?; assert(entry.key == keys[0]); assert(entry.value == values[0]); } diff --git a/std/heap.zig b/std/heap.zig index 5d430bc761..d1fbf9ca0a 100644 --- a/std/heap.zig +++ b/std/heap.zig @@ -142,7 +142,7 @@ pub const DirectAllocator = struct { const root_addr = @intToPtr(*align(1) usize, old_record_addr).*; const old_ptr = @intToPtr(*c_void, root_addr); const amt = new_size + alignment + @sizeOf(usize); - const new_ptr = os.windows.HeapReAlloc(??self.heap_handle, 0, old_ptr, amt) ?? blk: { + const new_ptr = os.windows.HeapReAlloc(self.heap_handle.?, 0, old_ptr, amt) ?? blk: { if (new_size > old_mem.len) return error.OutOfMemory; const new_record_addr = old_record_addr - new_size + old_mem.len; @intToPtr(*align(1) usize, new_record_addr).* = root_addr; @@ -171,7 +171,7 @@ pub const DirectAllocator = struct { const record_addr = @ptrToInt(bytes.ptr) + bytes.len; const root_addr = @intToPtr(*align(1) usize, record_addr).*; const ptr = @intToPtr(*c_void, root_addr); - _ = os.windows.HeapFree(??self.heap_handle, 0, ptr); + _ = os.windows.HeapFree(self.heap_handle.?, 0, ptr); }, else => @compileError("Unsupported OS"), } diff --git a/std/json.zig b/std/json.zig index 03b19a7fa4..75ea2eee1c 100644 --- a/std/json.zig +++ b/std/json.zig @@ -908,7 +908,7 @@ pub const TokenStream = struct { }; fn checkNext(p: *TokenStream, id: Token.Id) void { - const token = ??(p.next() catch unreachable); + const token = (p.next() catch unreachable).?; debug.assert(token.id == id); } @@ -1376,17 +1376,17 @@ test "json parser dynamic" { var root = tree.root; - var image = (??root.Object.get("Image")).value; + var image = root.Object.get("Image").?.value; - const width = (??image.Object.get("Width")).value; + const width = image.Object.get("Width").?.value; debug.assert(width.Integer == 800); - const height = (??image.Object.get("Height")).value; + const height = image.Object.get("Height").?.value; debug.assert(height.Integer == 600); - const title = (??image.Object.get("Title")).value; + const title = image.Object.get("Title").?.value; debug.assert(mem.eql(u8, title.String, "View from 15th Floor")); - const animated = (??image.Object.get("Animated")).value; + const animated = image.Object.get("Animated").?.value; debug.assert(animated.Bool == false); } diff --git a/std/linked_list.zig b/std/linked_list.zig index fbc0a0c42a..536c6d24d0 100644 --- a/std/linked_list.zig +++ b/std/linked_list.zig @@ -270,8 +270,8 @@ test "basic linked list test" { var last = list.pop(); // {2, 3, 4} list.remove(three); // {2, 4} - assert((??list.first).data == 2); - assert((??list.last).data == 4); + assert(list.first.?.data == 2); + assert(list.last.?.data == 4); assert(list.len == 2); } @@ -336,7 +336,7 @@ test "basic intrusive linked list test" { var last = list.pop(); // {2, 3, 4} list.remove(&three.link); // {2, 4} - assert((??list.first).toData().value == 2); - assert((??list.last).toData().value == 4); + assert(list.first.?.toData().value == 2); + assert(list.last.?.toData().value == 4); assert(list.len == 2); } diff --git a/std/macho.zig b/std/macho.zig index d6eef9a325..64f78ae4a3 100644 --- a/std/macho.zig +++ b/std/macho.zig @@ -130,7 +130,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable for (syms) |sym| { if (!isSymbol(sym)) continue; const start = sym.n_strx; - const end = ??mem.indexOfScalarPos(u8, strings, start, 0); + const end = mem.indexOfScalarPos(u8, strings, start, 0).?; const name = strings[start..end]; const address = sym.n_value; symbols[nsym] = Symbol{ .name = name, .address = address }; diff --git a/std/mem.zig b/std/mem.zig index 423460e73b..f961c7862b 100644 --- a/std/mem.zig +++ b/std/mem.zig @@ -304,20 +304,20 @@ pub fn indexOfPos(comptime T: type, haystack: []const T, start_index: usize, nee } test "mem.indexOf" { - assert(??indexOf(u8, "one two three four", "four") == 14); - assert(??lastIndexOf(u8, "one two three two four", "two") == 14); + assert(indexOf(u8, "one two three four", "four").? == 14); + assert(lastIndexOf(u8, "one two three two four", "two").? == 14); assert(indexOf(u8, "one two three four", "gour") == null); assert(lastIndexOf(u8, "one two three four", "gour") == null); - assert(??indexOf(u8, "foo", "foo") == 0); - assert(??lastIndexOf(u8, "foo", "foo") == 0); + assert(indexOf(u8, "foo", "foo").? == 0); + assert(lastIndexOf(u8, "foo", "foo").? == 0); assert(indexOf(u8, "foo", "fool") == null); assert(lastIndexOf(u8, "foo", "lfoo") == null); assert(lastIndexOf(u8, "foo", "fool") == null); - assert(??indexOf(u8, "foo foo", "foo") == 0); - assert(??lastIndexOf(u8, "foo foo", "foo") == 4); - assert(??lastIndexOfAny(u8, "boo, cat", "abo") == 6); - assert(??lastIndexOfScalar(u8, "boo", 'o') == 2); + assert(indexOf(u8, "foo foo", "foo").? == 0); + assert(lastIndexOf(u8, "foo foo", "foo").? == 4); + assert(lastIndexOfAny(u8, "boo, cat", "abo").? == 6); + assert(lastIndexOfScalar(u8, "boo", 'o').? == 2); } /// Reads an integer from memory with size equal to bytes.len. @@ -432,9 +432,9 @@ pub fn split(buffer: []const u8, split_bytes: []const u8) SplitIterator { test "mem.split" { var it = split(" abc def ghi ", " "); - assert(eql(u8, ??it.next(), "abc")); - assert(eql(u8, ??it.next(), "def")); - assert(eql(u8, ??it.next(), "ghi")); + assert(eql(u8, it.next().?, "abc")); + assert(eql(u8, it.next().?, "def")); + assert(eql(u8, it.next().?, "ghi")); assert(it.next() == null); } diff --git a/std/os/child_process.zig b/std/os/child_process.zig index 822ade2eb8..1e3a732498 100644 --- a/std/os/child_process.zig +++ b/std/os/child_process.zig @@ -156,7 +156,7 @@ pub const ChildProcess = struct { }; } try self.waitUnwrappedWindows(); - return ??self.term; + return self.term.?; } pub fn killPosix(self: *ChildProcess) !Term { @@ -175,7 +175,7 @@ pub const ChildProcess = struct { }; } self.waitUnwrapped(); - return ??self.term; + return self.term.?; } /// Blocks until child process terminates and then cleans up all resources. @@ -212,8 +212,8 @@ pub const ChildProcess = struct { defer Buffer.deinit(&stdout); defer Buffer.deinit(&stderr); - var stdout_file_in_stream = io.FileInStream.init(&??child.stdout); - var stderr_file_in_stream = io.FileInStream.init(&??child.stderr); + var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); + var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); try stdout_file_in_stream.stream.readAllBuffer(&stdout, max_output_size); try stderr_file_in_stream.stream.readAllBuffer(&stderr, max_output_size); @@ -232,7 +232,7 @@ pub const ChildProcess = struct { } try self.waitUnwrappedWindows(); - return ??self.term; + return self.term.?; } fn waitPosix(self: *ChildProcess) !Term { @@ -242,7 +242,7 @@ pub const ChildProcess = struct { } self.waitUnwrapped(); - return ??self.term; + return self.term.?; } pub fn deinit(self: *ChildProcess) void { @@ -619,13 +619,13 @@ pub const ChildProcess = struct { self.term = null; if (self.stdin_behavior == StdIo.Pipe) { - os.close(??g_hChildStd_IN_Rd); + os.close(g_hChildStd_IN_Rd.?); } if (self.stderr_behavior == StdIo.Pipe) { - os.close(??g_hChildStd_ERR_Wr); + os.close(g_hChildStd_ERR_Wr.?); } if (self.stdout_behavior == StdIo.Pipe) { - os.close(??g_hChildStd_OUT_Wr); + os.close(g_hChildStd_OUT_Wr.?); } } diff --git a/std/os/index.zig b/std/os/index.zig index fe5ecc38ba..807b2c398b 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -422,7 +422,7 @@ pub fn posixExecve(argv: []const []const u8, env_map: *const BufMap, allocator: const exe_path = argv[0]; if (mem.indexOfScalar(u8, exe_path, '/') != null) { - return posixExecveErrnoToErr(posix.getErrno(posix.execve(??argv_buf[0], argv_buf.ptr, envp_buf.ptr))); + return posixExecveErrnoToErr(posix.getErrno(posix.execve(argv_buf[0].?, argv_buf.ptr, envp_buf.ptr))); } const PATH = getEnvPosix("PATH") ?? "/usr/local/bin:/bin/:/usr/bin"; @@ -1729,7 +1729,7 @@ test "windows arg parsing" { fn testWindowsCmdLine(input_cmd_line: [*]const u8, expected_args: []const []const u8) void { var it = ArgIteratorWindows.initWithCmdLine(input_cmd_line); for (expected_args) |expected_arg| { - const arg = ??it.next(debug.global_allocator) catch unreachable; + const arg = it.next(debug.global_allocator).? catch unreachable; assert(mem.eql(u8, arg, expected_arg)); } assert(it.next(debug.global_allocator) == null); diff --git a/std/os/linux/vdso.zig b/std/os/linux/vdso.zig index 2ab4d0cbc1..1414b8185b 100644 --- a/std/os/linux/vdso.zig +++ b/std/os/linux/vdso.zig @@ -67,7 +67,7 @@ pub fn lookup(vername: []const u8, name: []const u8) usize { if (0 == syms[i].st_shndx) continue; if (!mem.eql(u8, name, cstr.toSliceConst(strings + syms[i].st_name))) continue; if (maybe_versym) |versym| { - if (!checkver(??maybe_verdef, versym[i], vername, strings)) + if (!checkver(maybe_verdef.?, versym[i], vername, strings)) continue; } return base + syms[i].st_value; diff --git a/std/os/path.zig b/std/os/path.zig index 4df6179bf5..430dda2934 100644 --- a/std/os/path.zig +++ b/std/os/path.zig @@ -265,7 +265,7 @@ fn networkShareServersEql(ns1: []const u8, ns2: []const u8) bool { var it2 = mem.split(ns2, []u8{sep2}); // TODO ASCII is wrong, we actually need full unicode support to compare paths. - return asciiEqlIgnoreCase(??it1.next(), ??it2.next()); + return asciiEqlIgnoreCase(it1.next().?, it2.next().?); } fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8) bool { @@ -286,7 +286,7 @@ fn compareDiskDesignators(kind: WindowsPath.Kind, p1: []const u8, p2: []const u8 var it2 = mem.split(p2, []u8{sep2}); // TODO ASCII is wrong, we actually need full unicode support to compare paths. - return asciiEqlIgnoreCase(??it1.next(), ??it2.next()) and asciiEqlIgnoreCase(??it1.next(), ??it2.next()); + return asciiEqlIgnoreCase(it1.next().?, it2.next().?) and asciiEqlIgnoreCase(it1.next().?, it2.next().?); }, } } @@ -414,8 +414,8 @@ pub fn resolveWindows(allocator: *Allocator, paths: []const []const u8) ![]u8 { WindowsPath.Kind.NetworkShare => { result = try allocator.alloc(u8, max_size); var it = mem.split(paths[first_index], "/\\"); - const server_name = ??it.next(); - const other_name = ??it.next(); + const server_name = it.next().?; + const other_name = it.next().?; result[result_index] = '\\'; result_index += 1; diff --git a/std/segmented_list.zig b/std/segmented_list.zig index a2f3607ad8..9f10f4d44a 100644 --- a/std/segmented_list.zig +++ b/std/segmented_list.zig @@ -364,7 +364,7 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void { assert(x == 0); } - assert(??list.pop() == 100); + assert(list.pop().? == 100); assert(list.len == 99); try list.pushMany([]i32{ @@ -373,9 +373,9 @@ fn testSegmentedList(comptime prealloc: usize, allocator: *Allocator) !void { 3, }); assert(list.len == 102); - assert(??list.pop() == 3); - assert(??list.pop() == 2); - assert(??list.pop() == 1); + assert(list.pop().? == 3); + assert(list.pop().? == 2); + assert(list.pop().? == 1); assert(list.len == 99); try list.pushMany([]const i32{}); diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index 8aefe4751f..dd37f1edb6 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -54,10 +54,10 @@ fn posixCallMainAndExit() noreturn { const argc = argc_ptr[0]; const argv = @ptrCast([*][*]u8, argc_ptr + 1); - const envp_nullable = @ptrCast([*]?[*]u8, argv + argc + 1); + const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1); var envp_count: usize = 0; - while (envp_nullable[envp_count]) |_| : (envp_count += 1) {} - const envp = @ptrCast([*][*]u8, envp_nullable)[0..envp_count]; + while (envp_optional[envp_count]) |_| : (envp_count += 1) {} + const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; if (builtin.os == builtin.Os.linux) { const auxv = @ptrCast([*]usize, envp.ptr + envp_count + 1); var i: usize = 0; diff --git a/std/special/builtin.zig b/std/special/builtin.zig index e537078924..e97b0a89e4 100644 --- a/std/special/builtin.zig +++ b/std/special/builtin.zig @@ -19,7 +19,7 @@ export fn memset(dest: ?[*]u8, c: u8, n: usize) ?[*]u8 { var index: usize = 0; while (index != n) : (index += 1) - (??dest)[index] = c; + dest.?[index] = c; return dest; } @@ -29,7 +29,7 @@ export fn memcpy(noalias dest: ?[*]u8, noalias src: ?[*]const u8, n: usize) ?[*] var index: usize = 0; while (index != n) : (index += 1) - (??dest)[index] = (??src)[index]; + dest.?[index] = src.?[index]; return dest; } @@ -40,13 +40,13 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) ?[*]u8 { if (@ptrToInt(dest) < @ptrToInt(src)) { var index: usize = 0; while (index != n) : (index += 1) { - (??dest)[index] = (??src)[index]; + dest.?[index] = src.?[index]; } } else { var index = n; while (index != 0) { index -= 1; - (??dest)[index] = (??src)[index]; + dest.?[index] = src.?[index]; } } diff --git a/std/unicode.zig b/std/unicode.zig index 3d1bebdb55..21ae12f59c 100644 --- a/std/unicode.zig +++ b/std/unicode.zig @@ -286,15 +286,15 @@ fn testUtf8IteratorOnAscii() void { const s = Utf8View.initComptime("abc"); var it1 = s.iterator(); - debug.assert(std.mem.eql(u8, "a", ??it1.nextCodepointSlice())); - debug.assert(std.mem.eql(u8, "b", ??it1.nextCodepointSlice())); - debug.assert(std.mem.eql(u8, "c", ??it1.nextCodepointSlice())); + debug.assert(std.mem.eql(u8, "a", it1.nextCodepointSlice().?)); + debug.assert(std.mem.eql(u8, "b", it1.nextCodepointSlice().?)); + debug.assert(std.mem.eql(u8, "c", it1.nextCodepointSlice().?)); debug.assert(it1.nextCodepointSlice() == null); var it2 = s.iterator(); - debug.assert(??it2.nextCodepoint() == 'a'); - debug.assert(??it2.nextCodepoint() == 'b'); - debug.assert(??it2.nextCodepoint() == 'c'); + debug.assert(it2.nextCodepoint().? == 'a'); + debug.assert(it2.nextCodepoint().? == 'b'); + debug.assert(it2.nextCodepoint().? == 'c'); debug.assert(it2.nextCodepoint() == null); } @@ -321,15 +321,15 @@ fn testUtf8ViewOk() void { const s = Utf8View.initComptime("東京市"); var it1 = s.iterator(); - debug.assert(std.mem.eql(u8, "東", ??it1.nextCodepointSlice())); - debug.assert(std.mem.eql(u8, "京", ??it1.nextCodepointSlice())); - debug.assert(std.mem.eql(u8, "市", ??it1.nextCodepointSlice())); + debug.assert(std.mem.eql(u8, "東", it1.nextCodepointSlice().?)); + debug.assert(std.mem.eql(u8, "京", it1.nextCodepointSlice().?)); + debug.assert(std.mem.eql(u8, "市", it1.nextCodepointSlice().?)); debug.assert(it1.nextCodepointSlice() == null); var it2 = s.iterator(); - debug.assert(??it2.nextCodepoint() == 0x6771); - debug.assert(??it2.nextCodepoint() == 0x4eac); - debug.assert(??it2.nextCodepoint() == 0x5e02); + debug.assert(it2.nextCodepoint().? == 0x6771); + debug.assert(it2.nextCodepoint().? == 0x4eac); + debug.assert(it2.nextCodepoint().? == 0x5e02); debug.assert(it2.nextCodepoint() == null); } diff --git a/std/zig/ast.zig b/std/zig/ast.zig index a4b64d5db2..defaded78a 100644 --- a/std/zig/ast.zig +++ b/std/zig/ast.zig @@ -1417,7 +1417,7 @@ pub const Node = struct { Range, Sub, SubWrap, - UnwrapMaybe, + UnwrapOptional, }; pub fn iterate(self: *InfixOp, index: usize) ?*Node { @@ -1475,7 +1475,7 @@ pub const Node = struct { Op.Range, Op.Sub, Op.SubWrap, - Op.UnwrapMaybe, + Op.UnwrapOptional, => {}, } @@ -1507,14 +1507,13 @@ pub const Node = struct { BitNot, BoolNot, Cancel, - MaybeType, + OptionalType, Negation, NegationWrap, Resume, PtrType: PtrInfo, SliceType: PtrInfo, Try, - UnwrapMaybe, }; pub const PtrInfo = struct { @@ -1557,12 +1556,12 @@ pub const Node = struct { Op.BitNot, Op.BoolNot, Op.Cancel, - Op.MaybeType, + Op.OptionalType, Op.Negation, Op.NegationWrap, Op.Try, Op.Resume, - Op.UnwrapMaybe, + Op.UnwrapOptional, Op.PointerType, => {}, } @@ -1619,6 +1618,7 @@ pub const Node = struct { ArrayInitializer: InitList, StructInitializer: InitList, Deref, + UnwrapOptional, pub const InitList = SegmentedList(*Node, 2); diff --git a/std/zig/parse.zig b/std/zig/parse.zig index 7faca8e11b..9f8ef3c3d6 100644 --- a/std/zig/parse.zig +++ b/std/zig/parse.zig @@ -711,7 +711,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { else => { // TODO: this is a special case. Remove this when #760 is fixed if (token_ptr.id == Token.Id.Keyword_error) { - if ((??tok_it.peek()).id == Token.Id.LBrace) { + if (tok_it.peek().?.id == Token.Id.LBrace) { const error_type_node = try arena.construct(ast.Node.ErrorType{ .base = ast.Node{ .id = ast.Node.Id.ErrorType }, .token = token_index, @@ -1434,8 +1434,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{ .id = Token.Id.AngleBracketRight, - .ptr = &??async_node.rangle_bracket, - }, + .ptr = &async_node.rangle_bracket.? }, }); try stack.append(State{ .TypeExprBegin = OptionalCtx{ .RequiredNull = &async_node.allocator_type } }); continue; @@ -1567,7 +1566,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .bit_range = null, }; // TODO https://github.com/ziglang/zig/issues/1022 - const align_info = &??addr_of_info.align_info; + const align_info = &addr_of_info.align_info.?; try stack.append(State{ .AlignBitRange = align_info }); try stack.append(State{ .Expression = OptionalCtx{ .Required = &align_info.node } }); @@ -1604,7 +1603,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { switch (token.ptr.id) { Token.Id.Colon => { align_info.bit_range = ast.Node.PrefixOp.PtrInfo.Align.BitRange(undefined); - const bit_range = &??align_info.bit_range; + const bit_range = &align_info.bit_range.?; try stack.append(State{ .ExpectToken = Token.Id.RParen }); try stack.append(State{ .Expression = OptionalCtx{ .Required = &bit_range.end } }); @@ -2144,7 +2143,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { State.CurlySuffixExpressionEnd => |opt_ctx| { const lhs = opt_ctx.get() ?? continue; - if ((??tok_it.peek()).id == Token.Id.Period) { + if (tok_it.peek().?.id == Token.Id.Period) { const node = try arena.construct(ast.Node.SuffixOp{ .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, .lhs = lhs, @@ -2326,6 +2325,17 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; continue; } + if (eatToken(&tok_it, &tree, Token.Id.QuestionMark)) |question_token| { + const node = try arena.construct(ast.Node.SuffixOp{ + .base = ast.Node{ .id = ast.Node.Id.SuffixOp }, + .lhs = lhs, + .op = ast.Node.SuffixOp.Op.UnwrapOptional, + .rtoken = question_token, + }); + opt_ctx.store(&node.base); + stack.append(State{ .SuffixOpExpressionEnd = opt_ctx.toRequired() }) catch unreachable; + continue; + } const node = try arena.construct(ast.Node.InfixOp{ .base = ast.Node{ .id = ast.Node.Id.InfixOp }, .lhs = lhs, @@ -2403,7 +2413,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree { .arrow_token = next_token_index, .return_type = undefined, }; - const return_type_ptr = &((??node.result).return_type); + const return_type_ptr = &node.result.?.return_type; try stack.append(State{ .Expression = OptionalCtx{ .Required = return_type_ptr } }); continue; }, @@ -2875,7 +2885,7 @@ const OptionalCtx = union(enum) { pub fn get(self: *const OptionalCtx) ?*ast.Node { switch (self.*) { OptionalCtx.Optional => |ptr| return ptr.*, - OptionalCtx.RequiredNull => |ptr| return ??ptr.*, + OptionalCtx.RequiredNull => |ptr| return ptr.*.?, OptionalCtx.Required => |ptr| return ptr.*, } } @@ -3237,7 +3247,7 @@ fn tokenIdToAssignment(id: *const Token.Id) ?ast.Node.InfixOp.Op { fn tokenIdToUnwrapExpr(id: @TagType(Token.Id)) ?ast.Node.InfixOp.Op { return switch (id) { Token.Id.Keyword_catch => ast.Node.InfixOp.Op{ .Catch = null }, - Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op{ .UnwrapMaybe = void{} }, + Token.Id.QuestionMarkQuestionMark => ast.Node.InfixOp.Op{ .UnwrapOptional = void{} }, else => null, }; } @@ -3299,8 +3309,7 @@ fn tokenIdToPrefixOp(id: @TagType(Token.Id)) ?ast.Node.PrefixOp.Op { .volatile_token = null, }, }, - Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .MaybeType = void{} }, - Token.Id.QuestionMarkQuestionMark => ast.Node.PrefixOp.Op{ .UnwrapMaybe = void{} }, + Token.Id.QuestionMark => ast.Node.PrefixOp.Op{ .OptionalType = void{} }, Token.Id.Keyword_await => ast.Node.PrefixOp.Op{ .Await = void{} }, Token.Id.Keyword_try => ast.Node.PrefixOp.Op{ .Try = void{} }, else => null, @@ -3322,7 +3331,7 @@ fn createToCtxLiteral(arena: *mem.Allocator, opt_ctx: *const OptionalCtx, compti } fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: @TagType(Token.Id)) ?TokenIndex { - const token = ??tok_it.peek(); + const token = tok_it.peek().?; if (token.id == id) { return nextToken(tok_it, tree).index; @@ -3334,7 +3343,7 @@ fn eatToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree, id: @TagType( fn nextToken(tok_it: *ast.Tree.TokenList.Iterator, tree: *ast.Tree) AnnotatedToken { const result = AnnotatedToken{ .index = tok_it.index, - .ptr = ??tok_it.next(), + .ptr = tok_it.next().?, }; assert(result.ptr.id != Token.Id.LineComment); diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 91a56de827..ea3a4858b0 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -650,9 +650,10 @@ test "zig fmt: statements with empty line between" { ); } -test "zig fmt: ptr deref operator" { +test "zig fmt: ptr deref operator and unwrap optional operator" { try testCanonical( \\const a = b.*; + \\const a = b.?; \\ ); } @@ -1209,7 +1210,7 @@ test "zig fmt: precedence" { test "zig fmt: prefix operators" { try testCanonical( \\test "prefix operators" { - \\ try return --%~??!*&0; + \\ try return --%~!*&0; \\} \\ ); diff --git a/std/zig/render.zig b/std/zig/render.zig index 7c9b53b77a..0b8e4d1453 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -222,7 +222,7 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i } } - const value_expr = ??tag.value_expr; + const value_expr = tag.value_expr.?; try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, start_col, Space.Space); // = try renderExpression(allocator, stream, tree, indent, start_col, value_expr, Space.Comma); // value, }, @@ -465,8 +465,7 @@ fn renderExpression( ast.Node.PrefixOp.Op.BoolNot, ast.Node.PrefixOp.Op.Negation, ast.Node.PrefixOp.Op.NegationWrap, - ast.Node.PrefixOp.Op.UnwrapMaybe, - ast.Node.PrefixOp.Op.MaybeType, + ast.Node.PrefixOp.Op.OptionalType, ast.Node.PrefixOp.Op.AddressOf, => { try renderToken(tree, stream, prefix_op_node.op_token, indent, start_col, Space.None); @@ -513,7 +512,7 @@ fn renderExpression( var it = call_info.params.iterator(0); while (true) { - const param_node = ??it.next(); + const param_node = it.next().?; const param_node_new_indent = if (param_node.*.id == ast.Node.Id.MultilineStringLiteral) blk: { break :blk indent; @@ -559,10 +558,10 @@ fn renderExpression( return renderToken(tree, stream, rbracket, indent, start_col, space); // ] }, - ast.Node.SuffixOp.Op.Deref => { + ast.Node.SuffixOp.Op.Deref, ast.Node.SuffixOp.Op.UnwrapOptional => { try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . - return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // * + return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // * or ? }, @TagType(ast.Node.SuffixOp.Op).Slice => |range| { @@ -595,7 +594,7 @@ fn renderExpression( } if (field_inits.len == 1) blk: { - const field_init = ??field_inits.at(0).*.cast(ast.Node.FieldInitializer); + const field_init = field_inits.at(0).*.cast(ast.Node.FieldInitializer).?; if (field_init.expr.cast(ast.Node.SuffixOp)) |nested_suffix_op| { if (nested_suffix_op.op == ast.Node.SuffixOp.Op.StructInitializer) { @@ -688,7 +687,7 @@ fn renderExpression( var count: usize = 1; var it = exprs.iterator(0); while (true) { - const expr = (??it.next()).*; + const expr = it.next().?.*; if (it.peek()) |next_expr| { const expr_last_token = expr.*.lastToken() + 1; const loc = tree.tokenLocation(tree.tokens.at(expr_last_token).end, next_expr.*.firstToken()); @@ -806,7 +805,7 @@ fn renderExpression( }, } - return renderExpression(allocator, stream, tree, indent, start_col, ??flow_expr.rhs, space); + return renderExpression(allocator, stream, tree, indent, start_col, flow_expr.rhs.?, space); }, ast.Node.Id.Payload => { @@ -1245,7 +1244,7 @@ fn renderExpression( } else { var it = switch_case.items.iterator(0); while (true) { - const node = ??it.next(); + const node = it.next().?; if (it.peek()) |next_node| { try renderExpression(allocator, stream, tree, indent, start_col, node.*, Space.None); @@ -1550,7 +1549,7 @@ fn renderExpression( var it = asm_node.outputs.iterator(0); while (true) { - const asm_output = ??it.next(); + const asm_output = it.next().?; const node = &(asm_output.*).base; if (it.peek()) |next_asm_output| { @@ -1588,7 +1587,7 @@ fn renderExpression( var it = asm_node.inputs.iterator(0); while (true) { - const asm_input = ??it.next(); + const asm_input = it.next().?; const node = &(asm_input.*).base; if (it.peek()) |next_asm_input| { @@ -1620,7 +1619,7 @@ fn renderExpression( var it = asm_node.clobbers.iterator(0); while (true) { - const clobber_token = ??it.next(); + const clobber_token = it.next().?; if (it.peek() == null) { try renderToken(tree, stream, clobber_token.*, indent_once, start_col, Space.Newline); diff --git a/test/cases/bugs/656.zig b/test/cases/bugs/656.zig index a6035d51bb..f93f0ac4d5 100644 --- a/test/cases/bugs/656.zig +++ b/test/cases/bugs/656.zig @@ -9,7 +9,7 @@ const Value = struct { align_expr: ?u32, }; -test "nullable if after an if in a switch prong of a switch with 2 prongs in an else" { +test "optional if after an if in a switch prong of a switch with 2 prongs in an else" { foo(false, true); } diff --git a/test/cases/cast.zig b/test/cases/cast.zig index da3cba7d80..a56c470408 100644 --- a/test/cases/cast.zig +++ b/test/cases/cast.zig @@ -109,16 +109,16 @@ test "implicitly cast indirect pointer to maybe-indirect pointer" { const Self = this; x: u8, fn constConst(p: *const *const Self) u8 { - return (p.*).x; + return p.*.x; } fn maybeConstConst(p: ?*const *const Self) u8 { - return ((??p).*).x; + return p.?.*.x; } fn constConstConst(p: *const *const *const Self) u8 { - return (p.*.*).x; + return p.*.*.x; } fn maybeConstConstConst(p: ?*const *const *const Self) u8 { - return ((??p).*.*).x; + return p.?.*.*.x; } }; const s = S{ .x = 42 }; @@ -177,56 +177,56 @@ test "string literal to &const []const u8" { } test "implicitly cast from T to error!?T" { - castToMaybeTypeError(1); - comptime castToMaybeTypeError(1); + castToOptionalTypeError(1); + comptime castToOptionalTypeError(1); } const A = struct { a: i32, }; -fn castToMaybeTypeError(z: i32) void { +fn castToOptionalTypeError(z: i32) void { const x = i32(1); const y: error!?i32 = x; - assert(??(try y) == 1); + assert((try y).? == 1); const f = z; const g: error!?i32 = f; const a = A{ .a = z }; const b: error!?A = a; - assert((??(b catch unreachable)).a == 1); + assert((b catch unreachable).?.a == 1); } test "implicitly cast from int to error!?T" { - implicitIntLitToMaybe(); - comptime implicitIntLitToMaybe(); + implicitIntLitToOptional(); + comptime implicitIntLitToOptional(); } -fn implicitIntLitToMaybe() void { +fn implicitIntLitToOptional() void { const f: ?i32 = 1; const g: error!?i32 = 1; } test "return null from fn() error!?&T" { - const a = returnNullFromMaybeTypeErrorRef(); - const b = returnNullLitFromMaybeTypeErrorRef(); + const a = returnNullFromOptionalTypeErrorRef(); + const b = returnNullLitFromOptionalTypeErrorRef(); assert((try a) == null and (try b) == null); } -fn returnNullFromMaybeTypeErrorRef() error!?*A { +fn returnNullFromOptionalTypeErrorRef() error!?*A { const a: ?*A = null; return a; } -fn returnNullLitFromMaybeTypeErrorRef() error!?*A { +fn returnNullLitFromOptionalTypeErrorRef() error!?*A { return null; } test "peer type resolution: ?T and T" { - assert(??peerTypeTAndMaybeT(true, false) == 0); - assert(??peerTypeTAndMaybeT(false, false) == 3); + assert(peerTypeTAndOptionalT(true, false).? == 0); + assert(peerTypeTAndOptionalT(false, false).? == 3); comptime { - assert(??peerTypeTAndMaybeT(true, false) == 0); - assert(??peerTypeTAndMaybeT(false, false) == 3); + assert(peerTypeTAndOptionalT(true, false).? == 0); + assert(peerTypeTAndOptionalT(false, false).? == 3); } } -fn peerTypeTAndMaybeT(c: bool, b: bool) ?usize { +fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { if (c) { return if (b) null else usize(0); } @@ -251,11 +251,11 @@ fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 { } test "implicitly cast from [N]T to ?[]const T" { - assert(mem.eql(u8, ??castToMaybeSlice(), "hi")); - comptime assert(mem.eql(u8, ??castToMaybeSlice(), "hi")); + assert(mem.eql(u8, castToOptionalSlice().?, "hi")); + comptime assert(mem.eql(u8, castToOptionalSlice().?, "hi")); } -fn castToMaybeSlice() ?[]const u8 { +fn castToOptionalSlice() ?[]const u8 { return "hi"; } @@ -404,5 +404,5 @@ fn testCastPtrOfArrayToSliceAndPtr() void { test "cast *[1][*]const u8 to [*]const ?[*]const u8" { const window_name = [1][*]const u8{c"window name"}; const x: [*]const ?[*]const u8 = &window_name; - assert(mem.eql(u8, std.cstr.toSliceConst(??x[0]), "window name")); + assert(mem.eql(u8, std.cstr.toSliceConst(x[0].?), "window name")); } diff --git a/test/cases/error.zig b/test/cases/error.zig index ced49419d5..693631fe2d 100644 --- a/test/cases/error.zig +++ b/test/cases/error.zig @@ -140,7 +140,7 @@ fn testComptimeTestErrorEmptySet(x: EmptyErrorSet!i32) void { if (x) |v| assert(v == 1234) else |err| @compileError("bad"); } -test "syntax: nullable operator in front of error union operator" { +test "syntax: optional operator in front of error union operator" { comptime { assert(?error!i32 == ?(error!i32)); } diff --git a/test/cases/eval.zig b/test/cases/eval.zig index 9612466a86..08d3f3a841 100644 --- a/test/cases/eval.zig +++ b/test/cases/eval.zig @@ -12,7 +12,7 @@ fn fibonacci(x: i32) i32 { } fn unwrapAndAddOne(blah: ?i32) i32 { - return ??blah + 1; + return blah.? + 1; } const should_be_1235 = unwrapAndAddOne(1234); test "static add one" { diff --git a/test/cases/generics.zig b/test/cases/generics.zig index a76990e2a1..52aa013989 100644 --- a/test/cases/generics.zig +++ b/test/cases/generics.zig @@ -127,7 +127,7 @@ test "generic fn with implicit cast" { }) == 0); } fn getByte(ptr: ?*const u8) u8 { - return (??ptr).*; + return ptr.?.*; } fn getFirstByte(comptime T: type, mem: []const T) u8 { return getByte(@ptrCast(*const u8, &mem[0])); diff --git a/test/cases/misc.zig b/test/cases/misc.zig index 369d8e5cf3..beb0d6d456 100644 --- a/test/cases/misc.zig +++ b/test/cases/misc.zig @@ -505,7 +505,7 @@ test "@typeId" { assert(@typeId(@typeOf(1.0)) == Tid.ComptimeFloat); assert(@typeId(@typeOf(undefined)) == Tid.Undefined); assert(@typeId(@typeOf(null)) == Tid.Null); - assert(@typeId(?i32) == Tid.Nullable); + assert(@typeId(?i32) == Tid.Optional); assert(@typeId(error!i32) == Tid.ErrorUnion); assert(@typeId(error) == Tid.ErrorSet); assert(@typeId(AnEnum) == Tid.Enum); diff --git a/test/cases/null.zig b/test/cases/null.zig index bd78990ff4..62565784ac 100644 --- a/test/cases/null.zig +++ b/test/cases/null.zig @@ -1,6 +1,6 @@ const assert = @import("std").debug.assert; -test "nullable type" { +test "optional type" { const x: ?bool = true; if (x) |y| { @@ -33,7 +33,7 @@ test "test maybe object and get a pointer to the inner value" { b.* = false; } - assert(??maybe_bool == false); + assert(maybe_bool.? == false); } test "rhs maybe unwrap return" { @@ -47,9 +47,9 @@ test "maybe return" { } fn maybeReturnImpl() void { - assert(??foo(1235)); + assert(foo(1235).?); if (foo(null) != null) unreachable; - assert(!??foo(1234)); + assert(!foo(1234).?); } fn foo(x: ?i32) ?bool { @@ -102,12 +102,12 @@ fn testTestNullRuntime(x: ?i32) void { assert(!(x != null)); } -test "nullable void" { - nullableVoidImpl(); - comptime nullableVoidImpl(); +test "optional void" { + optionalVoidImpl(); + comptime optionalVoidImpl(); } -fn nullableVoidImpl() void { +fn optionalVoidImpl() void { assert(bar(null) == null); assert(bar({}) != null); } @@ -120,19 +120,19 @@ fn bar(x: ?void) ?void { } } -const StructWithNullable = struct { +const StructWithOptional = struct { field: ?i32, }; -var struct_with_nullable: StructWithNullable = undefined; +var struct_with_optional: StructWithOptional = undefined; -test "unwrap nullable which is field of global var" { - struct_with_nullable.field = null; - if (struct_with_nullable.field) |payload| { +test "unwrap optional which is field of global var" { + struct_with_optional.field = null; + if (struct_with_optional.field) |payload| { unreachable; } - struct_with_nullable.field = 1234; - if (struct_with_nullable.field) |payload| { + struct_with_optional.field = 1234; + if (struct_with_optional.field) |payload| { assert(payload == 1234); } else { unreachable; diff --git a/test/cases/reflection.zig b/test/cases/reflection.zig index 48fcc9ef03..3d3af3c889 100644 --- a/test/cases/reflection.zig +++ b/test/cases/reflection.zig @@ -2,7 +2,7 @@ const assert = @import("std").debug.assert; const mem = @import("std").mem; const reflection = this; -test "reflection: array, pointer, nullable, error union type child" { +test "reflection: array, pointer, optional, error union type child" { comptime { assert(([10]u8).Child == u8); assert((*u8).Child == u8); diff --git a/test/cases/type_info.zig b/test/cases/type_info.zig index b452c8e9f6..1bc58b14e1 100644 --- a/test/cases/type_info.zig +++ b/test/cases/type_info.zig @@ -88,15 +88,15 @@ fn testArray() void { assert(arr_info.Array.child == bool); } -test "type info: nullable type info" { - testNullable(); - comptime testNullable(); +test "type info: optional type info" { + testOptional(); + comptime testOptional(); } -fn testNullable() void { +fn testOptional() void { const null_info = @typeInfo(?void); - assert(TypeId(null_info) == TypeId.Nullable); - assert(null_info.Nullable.child == void); + assert(TypeId(null_info) == TypeId.Optional); + assert(null_info.Optional.child == void); } test "type info: promise info" { @@ -168,7 +168,7 @@ fn testUnion() void { assert(typeinfo_info.Union.tag_type == TypeId); assert(typeinfo_info.Union.fields.len == 25); assert(typeinfo_info.Union.fields[4].enum_field != null); - assert((??typeinfo_info.Union.fields[4].enum_field).value == 4); + assert(typeinfo_info.Union.fields[4].enum_field.?.value == 4); assert(typeinfo_info.Union.fields[4].field_type == @typeOf(@typeInfo(u8).Int)); assert(typeinfo_info.Union.defs.len == 20); diff --git a/test/cases/while.zig b/test/cases/while.zig index a95481668d..fe53522ea6 100644 --- a/test/cases/while.zig +++ b/test/cases/while.zig @@ -81,7 +81,7 @@ test "while with else" { assert(got_else == 1); } -test "while with nullable as condition" { +test "while with optional as condition" { numbers_left = 10; var sum: i32 = 0; while (getNumberOrNull()) |value| { @@ -90,7 +90,7 @@ test "while with nullable as condition" { assert(sum == 45); } -test "while with nullable as condition with else" { +test "while with optional as condition with else" { numbers_left = 10; var sum: i32 = 0; var got_else: i32 = 0; @@ -132,7 +132,7 @@ fn getNumberOrNull() ?i32 { }; } -test "while on nullable with else result follow else prong" { +test "while on optional with else result follow else prong" { const result = while (returnNull()) |value| { break value; } else @@ -140,8 +140,8 @@ test "while on nullable with else result follow else prong" { assert(result == 2); } -test "while on nullable with else result follow break prong" { - const result = while (returnMaybe(10)) |value| { +test "while on optional with else result follow break prong" { + const result = while (returnOptional(10)) |value| { break value; } else i32(2); @@ -210,7 +210,7 @@ fn testContinueOuter() void { fn returnNull() ?i32 { return null; } -fn returnMaybe(x: i32) ?i32 { +fn returnOptional(x: i32) ?i32 { return x; } fn returnError() error!i32 { diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 102c4e428d..1c737a59e7 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1341,7 +1341,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ if (true) |x| { } \\} , - ".tmp_source.zig:2:9: error: expected nullable type, found 'bool'", + ".tmp_source.zig:2:9: error: expected optional type, found 'bool'", ); cases.add( @@ -1780,7 +1780,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "assign null to non-nullable pointer", + "assign null to non-optional pointer", \\const a: *u8 = null; \\ \\export fn entry() usize { return @sizeOf(@typeOf(a)); } @@ -2817,7 +2817,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "while expected bool, got nullable", + "while expected bool, got optional", \\export fn foo() void { \\ while (bar()) {} \\} @@ -2837,23 +2837,23 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "while expected nullable, got bool", + "while expected optional, got bool", \\export fn foo() void { \\ while (bar()) |x| {} \\} \\fn bar() bool { return true; } , - ".tmp_source.zig:2:15: error: expected nullable type, found 'bool'", + ".tmp_source.zig:2:15: error: expected optional type, found 'bool'", ); cases.add( - "while expected nullable, got error union", + "while expected optional, got error union", \\export fn foo() void { \\ while (bar()) |x| {} \\} \\fn bar() error!i32 { return 1; } , - ".tmp_source.zig:2:15: error: expected nullable type, found 'error!i32'", + ".tmp_source.zig:2:15: error: expected optional type, found 'error!i32'", ); cases.add( @@ -2867,7 +2867,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { ); cases.add( - "while expected error union, got nullable", + "while expected error union, got optional", \\export fn foo() void { \\ while (bar()) |x| {} else |err| {} \\} diff --git a/test/tests.zig b/test/tests.zig index cc562331fe..b66441f628 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -282,8 +282,8 @@ pub const CompareOutputContext = struct { var stdout = Buffer.initNull(b.allocator); var stderr = Buffer.initNull(b.allocator); - var stdout_file_in_stream = io.FileInStream.init(&??child.stdout); - var stderr_file_in_stream = io.FileInStream.init(&??child.stderr); + var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); + var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); stdout_file_in_stream.stream.readAllBuffer(&stdout, max_stdout_size) catch unreachable; stderr_file_in_stream.stream.readAllBuffer(&stderr, max_stdout_size) catch unreachable; @@ -601,8 +601,8 @@ pub const CompileErrorContext = struct { var stdout_buf = Buffer.initNull(b.allocator); var stderr_buf = Buffer.initNull(b.allocator); - var stdout_file_in_stream = io.FileInStream.init(&??child.stdout); - var stderr_file_in_stream = io.FileInStream.init(&??child.stderr); + var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); + var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable; stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable; @@ -872,8 +872,8 @@ pub const TranslateCContext = struct { var stdout_buf = Buffer.initNull(b.allocator); var stderr_buf = Buffer.initNull(b.allocator); - var stdout_file_in_stream = io.FileInStream.init(&??child.stdout); - var stderr_file_in_stream = io.FileInStream.init(&??child.stderr); + var stdout_file_in_stream = io.FileInStream.init(&child.stdout.?); + var stderr_file_in_stream = io.FileInStream.init(&child.stderr.?); stdout_file_in_stream.stream.readAllBuffer(&stdout_buf, max_stdout_size) catch unreachable; stderr_file_in_stream.stream.readAllBuffer(&stderr_buf, max_stdout_size) catch unreachable; -- cgit v1.2.3 From 03c16c6c548a8f8246c3dcff540482b7612aab80 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 11 Jun 2018 14:58:42 -0400 Subject: implement @tagName as a switch instead of table lookup closes #976 closes #1080 --- src/all_types.hpp | 6 +- src/codegen.cpp | 172 ++++++++++++++++++++++++++++++---------------------- src/ir.cpp | 5 -- test/cases/enum.zig | 9 +++ 4 files changed, 112 insertions(+), 80 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index ab219e4e56..0d364915f9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1091,8 +1091,7 @@ struct TypeTableEntryEnum { bool zero_bits_loop_flag; bool zero_bits_known; - bool generate_name_table; - LLVMValueRef name_table; + LLVMValueRef name_function; HashMap fields_by_name; }; @@ -1411,6 +1410,7 @@ enum PanicMsgId { PanicMsgIdInvalidErrorCode, PanicMsgIdIncorrectAlignment, PanicMsgIdBadUnionField, + PanicMsgIdBadEnumValue, PanicMsgIdCount, }; @@ -1730,8 +1730,6 @@ struct CodeGen { ZigList link_objects; ZigList assembly_files; - ZigList name_table_enums; - Buf *test_filter; Buf *test_name_prefix; diff --git a/src/codegen.cpp b/src/codegen.cpp index da08ecfc9e..d05bcba2ce 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -875,6 +875,8 @@ static Buf *panic_msg_buf(PanicMsgId msg_id) { return buf_create_from_str("incorrect alignment"); case PanicMsgIdBadUnionField: return buf_create_from_str("access of inactive union field"); + case PanicMsgIdBadEnumValue: + return buf_create_from_str("invalid enum value"); } zig_unreachable(); } @@ -3516,34 +3518,112 @@ static LLVMValueRef ir_render_err_name(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, ""); } +static LLVMValueRef get_enum_tag_name_function(CodeGen *g, TypeTableEntry *enum_type) { + assert(enum_type->id == TypeTableEntryIdEnum); + if (enum_type->data.enumeration.name_function) + return enum_type->data.enumeration.name_function; + + TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, false, false, + PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0); + TypeTableEntry *u8_slice_type = get_slice_type(g, u8_ptr_type); + TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; + + LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(u8_slice_type->type_ref, 0), + &tag_int_type->type_ref, 1, false); + + Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false); + LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref); + LLVMSetLinkage(fn_val, LLVMInternalLinkage); + LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified)); + addLLVMFnAttr(fn_val, "nounwind"); + add_uwtable_attr(g, fn_val); + if (g->build_mode == BuildModeDebug) { + ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true"); + ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr); + } + + LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder); + LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder); + FnTableEntry *prev_cur_fn = g->cur_fn; + LLVMValueRef prev_cur_fn_val = g->cur_fn_val; + + LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry"); + LLVMPositionBuilderAtEnd(g->builder, entry_block); + ZigLLVMClearCurrentDebugLocation(g->builder); + g->cur_fn = nullptr; + g->cur_fn_val = fn_val; + + size_t field_count = enum_type->data.enumeration.src_field_count; + LLVMBasicBlockRef bad_value_block = LLVMAppendBasicBlock(g->cur_fn_val, "BadValue"); + LLVMValueRef tag_int_value = LLVMGetParam(fn_val, 0); + LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, tag_int_value, bad_value_block, field_count); + + + TypeTableEntry *usize = g->builtin_types.entry_usize; + LLVMValueRef array_ptr_indices[] = { + LLVMConstNull(usize->type_ref), + LLVMConstNull(usize->type_ref), + }; + + for (size_t field_i = 0; field_i < field_count; field_i += 1) { + Buf *name = enum_type->data.enumeration.fields[field_i].name; + LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true); + LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); + LLVMSetInitializer(str_global, str_init); + LLVMSetLinkage(str_global, LLVMPrivateLinkage); + LLVMSetGlobalConstant(str_global, true); + LLVMSetUnnamedAddr(str_global, true); + LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init))); + + LLVMValueRef fields[] = { + LLVMConstGEP(str_global, array_ptr_indices, 2), + LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false), + }; + LLVMValueRef slice_init_value = LLVMConstNamedStruct(u8_slice_type->type_ref, fields, 2); + + LLVMValueRef slice_global = LLVMAddGlobal(g->module, LLVMTypeOf(slice_init_value), ""); + LLVMSetInitializer(slice_global, slice_init_value); + LLVMSetLinkage(slice_global, LLVMPrivateLinkage); + LLVMSetGlobalConstant(slice_global, true); + LLVMSetUnnamedAddr(slice_global, true); + LLVMSetAlignment(slice_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(slice_init_value))); + + LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn_val, "Name"); + LLVMValueRef this_tag_int_value = bigint_to_llvm_const(tag_int_type->type_ref, + &enum_type->data.enumeration.fields[field_i].value); + LLVMAddCase(switch_instr, this_tag_int_value, return_block); + + LLVMPositionBuilderAtEnd(g->builder, return_block); + LLVMBuildRet(g->builder, slice_global); + } + + LLVMPositionBuilderAtEnd(g->builder, bad_value_block); + if (g->build_mode == BuildModeDebug || g->build_mode == BuildModeSafeRelease) { + gen_safety_crash(g, PanicMsgIdBadEnumValue); + } else { + LLVMBuildUnreachable(g->builder); + } + + g->cur_fn = prev_cur_fn; + g->cur_fn_val = prev_cur_fn_val; + LLVMPositionBuilderAtEnd(g->builder, prev_block); + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + + enum_type->data.enumeration.name_function = fn_val; + return fn_val; +} + static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable, IrInstructionTagName *instruction) { TypeTableEntry *enum_type = instruction->target->value.type; assert(enum_type->id == TypeTableEntryIdEnum); - assert(enum_type->data.enumeration.generate_name_table); - TypeTableEntry *tag_int_type = enum_type->data.enumeration.tag_int_type; - LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); - if (ir_want_runtime_safety(g, &instruction->base)) { - size_t field_count = enum_type->data.enumeration.src_field_count; - - // if the field_count can't fit in the bits of the enum_type, then it can't possibly - // be the wrong value - BigInt field_bi; - bigint_init_unsigned(&field_bi, field_count); - if (bigint_fits_in_bits(&field_bi, tag_int_type->data.integral.bit_count, false)) { - LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(enum_tag_value), field_count, false); - add_bounds_check(g, enum_tag_value, LLVMIntEQ, nullptr, LLVMIntULT, end_val); - } - } + LLVMValueRef enum_name_function = get_enum_tag_name_function(g, enum_type); - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->type_ref), - gen_widen_or_shorten(g, false, tag_int_type, - g->builtin_types.entry_usize, enum_tag_value), - }; - return LLVMBuildInBoundsGEP(g->builder, enum_type->data.enumeration.name_table, indices, 2, ""); + LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); + return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1, + get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); } static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable, @@ -5471,55 +5551,6 @@ static void generate_error_name_table(CodeGen *g) { LLVMSetAlignment(g->err_name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(err_name_table_init))); } -static void generate_enum_name_tables(CodeGen *g) { - TypeTableEntry *u8_ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, - PtrLenUnknown, get_abi_alignment(g, g->builtin_types.entry_u8), 0, 0); - TypeTableEntry *str_type = get_slice_type(g, u8_ptr_type); - - TypeTableEntry *usize = g->builtin_types.entry_usize; - LLVMValueRef array_ptr_indices[] = { - LLVMConstNull(usize->type_ref), - LLVMConstNull(usize->type_ref), - }; - - - for (size_t enum_i = 0; enum_i < g->name_table_enums.length; enum_i += 1) { - TypeTableEntry *enum_type = g->name_table_enums.at(enum_i); - assert(enum_type->id == TypeTableEntryIdEnum); - - size_t field_count = enum_type->data.enumeration.src_field_count; - LLVMValueRef *values = allocate(field_count); - for (size_t field_i = 0; field_i < field_count; field_i += 1) { - Buf *name = enum_type->data.enumeration.fields[field_i].name; - - LLVMValueRef str_init = LLVMConstString(buf_ptr(name), (unsigned)buf_len(name), true); - LLVMValueRef str_global = LLVMAddGlobal(g->module, LLVMTypeOf(str_init), ""); - LLVMSetInitializer(str_global, str_init); - LLVMSetLinkage(str_global, LLVMPrivateLinkage); - LLVMSetGlobalConstant(str_global, true); - LLVMSetUnnamedAddr(str_global, true); - LLVMSetAlignment(str_global, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(str_init))); - - LLVMValueRef fields[] = { - LLVMConstGEP(str_global, array_ptr_indices, 2), - LLVMConstInt(g->builtin_types.entry_usize->type_ref, buf_len(name), false), - }; - values[field_i] = LLVMConstNamedStruct(str_type->type_ref, fields, 2); - } - - LLVMValueRef name_table_init = LLVMConstArray(str_type->type_ref, values, (unsigned)field_count); - - Buf *table_name = get_mangled_name(g, buf_sprintf("%s_name_table", buf_ptr(&enum_type->name)), false); - LLVMValueRef name_table = LLVMAddGlobal(g->module, LLVMTypeOf(name_table_init), buf_ptr(table_name)); - LLVMSetInitializer(name_table, name_table_init); - LLVMSetLinkage(name_table, LLVMPrivateLinkage); - LLVMSetGlobalConstant(name_table, true); - LLVMSetUnnamedAddr(name_table, true); - LLVMSetAlignment(name_table, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(name_table_init))); - enum_type->data.enumeration.name_table = name_table; - } -} - static void build_all_basic_blocks(CodeGen *g, FnTableEntry *fn) { IrExecutable *executable = &fn->analyzed_executable; assert(executable->basic_block_list.length > 0); @@ -5616,7 +5647,6 @@ static void do_code_gen(CodeGen *g) { } generate_error_name_table(g); - generate_enum_name_tables(g); // Generate module level variables for (size_t i = 0; i < g->global_vars.length; i += 1) { diff --git a/src/ir.cpp b/src/ir.cpp index 38f4dc90e7..4b6d5fdcf1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15837,11 +15837,6 @@ static TypeTableEntry *ir_analyze_instruction_enum_tag_name(IrAnalyze *ira, IrIn return out_val->type; } - if (!target->value.type->data.enumeration.generate_name_table) { - target->value.type->data.enumeration.generate_name_table = true; - ira->codegen->name_table_enums.append(target->value.type); - } - IrInstruction *result = ir_build_tag_name(&ira->new_irb, instruction->base.scope, instruction->base.source_node, target); ir_link_new_instruction(result, &instruction->base); diff --git a/test/cases/enum.zig b/test/cases/enum.zig index ae9f04869b..5c78d73092 100644 --- a/test/cases/enum.zig +++ b/test/cases/enum.zig @@ -883,3 +883,12 @@ test "empty extern enum with members" { }; assert(@sizeOf(E) == @sizeOf(c_int)); } + +test "aoeu" { + const LocalFoo = enum { + A = 1, + B = 0, + }; + var b = LocalFoo.B; + assert(mem.eql(u8, @tagName(b), "B")); +} -- cgit v1.2.3