From 7c15c9428e9df26c8699f034704796b03cf839b9 Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 18 Aug 2020 12:24:23 +0300 Subject: stage2: array types --- src-self-hosted/Module.zig | 67 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 6e33101e76..3c31c7da44 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2902,7 +2902,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: return Value.initPayload(val_payload); } -pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type { +pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type { const type_payload = try scope.arena().create(Type.Payload.Pointer); type_payload.* = .{ .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer }, @@ -2911,6 +2911,71 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el return Type.initPayload(&type_payload.base); } +pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { + return Type.initPayload(switch (child_type.tag()) { + .single_const_pointer => blk: { + const payload = try scope.arena().create(Type.Payload.Pointer); + payload.* = .{ + .base = .{ .tag = .optional_single_const_pointer }, + .pointee_type = child_type.elemType(), + }; + break :blk &payload.base; + }, + .single_mut_pointer => blk: { + const payload = try scope.arena().create(Type.Payload.Pointer); + payload.* = .{ + .base = .{ .tag = .optional_single_mut_pointer }, + .pointee_type = child_type.elemType(), + }; + break :blk &payload.base; + }, + else => blk: { + const payload = try scope.arena().create(Type.Payload.Optional); + payload.* = .{ + .child_type = child_type, + }; + break :blk &payload.base; + }, + }); +} + +pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type { + if (elem_type.eql(Type.initTag(.u8))) { + if (sentinel) |some| { + if (some.eql(Value.initTag(.zero))) { + const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0); + payload.* = .{ + .len = len, + }; + return Type.initPayload(&payload.base); + } + } else { + const payload = try scope.arena().create(Type.Payload.Array_u8); + payload.* = .{ + .len = len, + }; + return Type.initPayload(&payload.base); + } + } + + if (sentinel) |some| { + const payload = try scope.arena().create(Type.Payload.ArraySentinel); + payload.* = .{ + .len = len, + .sentinel = some, + .elem_type = elem_type, + }; + return Type.initPayload(&payload.base); + } + + const payload = try scope.arena().create(Type.Payload.Array); + payload.* = .{ + .len = len, + .elem_type = elem_type, + }; + return Type.initPayload(&payload.base); +} + pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void { const zir_module = scope.namespace(); const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source"); -- cgit v1.2.3 From dc35b8641badf3169a3124e84b672c3bf4bfd5f8 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Aug 2020 20:10:27 -0700 Subject: stage2: Module enumerates the possible top level decls --- src-self-hosted/Module.zig | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 3c31c7da44..e5988dfd8a 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1583,11 +1583,19 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { } } } + } else if (src_decl.castTag(.VarDecl)) |var_decl| { + log.err("TODO: analyze var decl", .{}); + } else if (src_decl.castTag(.Comptime)) |comptime_node| { + log.err("TODO: analyze comptime decl", .{}); + } else if (src_decl.castTag(.ContainerField)) |container_field| { + log.err("TODO: analyze container field", .{}); + } else if (src_decl.castTag(.TestDecl)) |test_decl| { + log.err("TODO: analyze test decl", .{}); + } else if (src_decl.castTag(.Use)) |use_decl| { + log.err("TODO: analyze usingnamespace decl", .{}); } else { - std.debug.panic("TODO: analyzeRootSrcFile {}", .{src_decl.tag}); + unreachable; } - // TODO also look for global variable declarations - // TODO also look for comptime blocks and exported globals } // Handle explicitly deleted decls from the source code. Not to be confused // with when we delete decls because they are no longer referenced. -- cgit v1.2.3 From 338a495648f07a2734e012034fd301a0e77f8202 Mon Sep 17 00:00:00 2001 From: Vexu Date: Wed, 19 Aug 2020 13:56:48 +0300 Subject: stage2: implement global variables --- src-self-hosted/Module.zig | 218 +++++++++++++++++++++++++++++++++++++++++-- src-self-hosted/codegen.zig | 11 +++ src-self-hosted/ir.zig | 16 ++++ src-self-hosted/type.zig | 6 +- src-self-hosted/value.zig | 19 ++++ src-self-hosted/zir.zig | 5 + src-self-hosted/zir_sema.zig | 4 +- 7 files changed, 266 insertions(+), 13 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index e5988dfd8a..3a68063236 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -320,6 +320,12 @@ pub const Fn = struct { } }; +pub const Var = struct { + value: ?Value, + owner_decl: *Decl, + is_mutable: bool, +}; + pub const Scope = struct { tag: Tag, @@ -1419,7 +1425,152 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { } return type_changed; }, - .VarDecl => @panic("TODO var decl"), + .VarDecl => { + const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", ast_node); + + decl.analysis = .in_progress; + + const is_extern = blk: { + const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse + break :blk false; + break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; + }; + const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; + + // We need the memory for the Type to go into the arena for the Decl + var decl_arena = std.heap.ArenaAllocator.init(self.gpa); + errdefer decl_arena.deinit(); + const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); + + var block_scope: Scope.Block = .{ + .parent = null, + .func = null, + .decl = decl, + .instructions = .{}, + .arena = &decl_arena.allocator, + }; + defer block_scope.instructions.deinit(self.gpa); + + const explicit_type = blk: { + const type_node = var_decl.getTrailer("type_node") orelse + break :blk null; + + var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); + defer type_scope_arena.deinit(); + var type_scope: Scope.GenZIR = .{ + .decl = decl, + .arena = &type_scope_arena.allocator, + .parent = decl.scope, + }; + defer type_scope.instructions.deinit(self.gpa); + + const src = tree.token_locs[type_node.firstToken()].start; + const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.type_type), + }); + const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node); + _ = try astgen.addZIRUnOp(self, &type_scope.base, src, .@"return", var_type); + + break :blk try zir_sema.analyzeBodyValueAsType(self, &block_scope, .{ + .instructions = type_scope.instructions.items, + }); + }; + + var var_type: Type = undefined; + const value: ?Value = if (var_decl.getTrailer("init_node")) |init_node| blk: { + var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa); + defer gen_scope_arena.deinit(); + var gen_scope: Scope.GenZIR = .{ + .decl = decl, + .arena = &gen_scope_arena.allocator, + .parent = decl.scope, + }; + defer gen_scope.instructions.deinit(self.gpa); + const src = tree.token_locs[init_node.firstToken()].start; + + // TODO comptime scope here + const init_inst = try astgen.expr(self, &gen_scope.base, .none, init_node); + _ = try astgen.addZIRUnOp(self, &gen_scope.base, src, .@"return", init_inst); + + var inner_block: Scope.Block = .{ + .parent = null, + .func = null, + .decl = decl, + .instructions = .{}, + .arena = &gen_scope_arena.allocator, + }; + defer inner_block.instructions.deinit(self.gpa); + try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items }); + + for (inner_block.instructions.items) |inst| { + if (inst.castTag(.ret)) |ret| { + const coerced = if (explicit_type) |some| + try self.coerce(&inner_block.base, some, ret.operand) + else + ret.operand; + const val = try self.resolveConstValue(&inner_block.base, coerced); + + var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); + break :blk try val.copy(block_scope.arena); + } else { + return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); + } + } + unreachable; + } else if (!is_extern) { + return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{}); + } else if (explicit_type) |some| blk: { + var_type = some; + break :blk null; + } else { + return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{}); + }; + + if (is_mutable and !var_type.isValidVarType(is_extern)) { + return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_type}); + } + + var type_changed = true; + if (decl.typedValueManaged()) |tvm| { + type_changed = !tvm.typed_value.ty.eql(var_type); + + tvm.deinit(self.gpa); + } + + const new_variable = try decl_arena.allocator.create(Var); + const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); + new_variable.* = .{ + .value = value, + .owner_decl = decl, + .is_mutable = is_mutable, + }; + var_payload.* = .{ .variable = new_variable }; + + decl_arena_state.* = decl_arena.state; + decl.typed_value = .{ + .most_recent = .{ + .typed_value = .{ + .ty = var_type, + .val = Value.initPayload(&var_payload.base), + }, + .arena = decl_arena_state, + }, + }; + decl.analysis = .complete; + decl.generation = self.generation; + + if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| { + if (tree.token_ids[maybe_export_token] == .Keyword_export) { + const export_src = tree.token_locs[maybe_export_token].start; + const name_loc = tree.token_locs[var_decl.name_token]; + const name = tree.tokenSliceLoc(name_loc); + // The scope needs to have the decl in it. + try self.analyzeExport(&block_scope.base, export_src, name, decl); + } + } + return type_changed; + }, .Comptime => @panic("TODO comptime decl"), .Use => @panic("TODO usingnamespace decl"), else => unreachable, @@ -1584,7 +1735,32 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { } } } else if (src_decl.castTag(.VarDecl)) |var_decl| { - log.err("TODO: analyze var decl", .{}); + const name_loc = tree.token_locs[var_decl.name_token]; + const name = tree.tokenSliceLoc(name_loc); + const name_hash = root_scope.fullyQualifiedNameHash(name); + const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); + if (self.decl_table.get(name_hash)) |decl| { + // Update the AST Node index of the decl, even if its contents are unchanged, it may + // have been re-ordered. + decl.src_index = decl_i; + if (deleted_decls.remove(decl) == null) { + decl.analysis = .sema_failure; + const err_msg = try ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name}); + errdefer err_msg.destroy(self.gpa); + try self.failed_decls.putNoClobber(self.gpa, decl, err_msg); + } else if (!srcHashEql(decl.contents_hash, contents_hash)) { + try self.markOutdatedDecl(decl); + decl.contents_hash = contents_hash; + } + } else { + const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); + root_scope.decls.appendAssumeCapacity(new_decl); + if (var_decl.getTrailer("extern_export_token")) |maybe_export_token| { + if (tree.token_ids[maybe_export_token] == .Keyword_export) { + self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); + } + } + } } else if (src_decl.castTag(.Comptime)) |comptime_node| { log.err("TODO: analyze comptime decl", .{}); } else if (src_decl.castTag(.ContainerField)) |container_field| { @@ -2217,20 +2393,46 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn }; const decl_tv = try decl.typedValue(); - const ty_payload = try scope.arena().create(Type.Payload.Pointer); - ty_payload.* = .{ - .base = .{ .tag = .single_const_pointer }, - .pointee_type = decl_tv.ty, - }; + if (decl_tv.val.tag() == .variable) { + return self.getVarRef(scope, src, decl_tv); + } + const ty = try self.singlePtrType(scope, src, false, decl_tv.ty); const val_payload = try scope.arena().create(Value.Payload.DeclRef); val_payload.* = .{ .decl = decl }; return self.constInst(scope, src, .{ - .ty = Type.initPayload(&ty_payload.base), + .ty = ty, .val = Value.initPayload(&val_payload.base), }); } +fn getVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { + const variable = tv.val.cast(Value.Payload.Variable).?.variable; + + const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); + if (!variable.is_mutable and variable.value != null) { + const val_payload = try scope.arena().create(Value.Payload.RefVal); + val_payload.* = .{ .val = variable.value.? }; + return self.constInst(scope, src, .{ + .ty = ty, + .val = Value.initPayload(&val_payload.base), + }); + } + + const b = try self.requireRuntimeBlock(scope, src); + const inst = try b.arena.create(Inst.VarPtr); + inst.* = .{ + .base = .{ + .tag = .varptr, + .ty = ty, + .src = src, + }, + .variable = variable, + }; + try b.instructions.append(self.gpa, &inst.base); + return &inst.base; +} + pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst { const elem_ty = switch (ptr.ty.zigTypeTag()) { .Pointer => ptr.ty.elemType(), diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index cb404d8315..1bc76f6b05 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -684,6 +684,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .unreach => return MCValue{ .unreach = {} }, .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?), .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?), + .varptr => return self.genVarPtr(inst.castTag(.varptr).?), } } @@ -858,6 +859,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } } + fn genVarPtr(self: *Self, inst: *ir.Inst.VarPtr) !MCValue { + // No side effects, so if it's unreferenced, do nothing. + if (inst.base.isUnused()) + return MCValue.dead; + + switch (arch) { + else => return self.fail(inst.base.src, "TODO implement varptr for {}", .{self.target.cpu.arch}), + } + } + fn reuseOperand(inst: *ir.Inst, op_index: ir.Inst.DeathsBitIndex, mcv: MCValue) bool { if (!inst.operandDies(op_index) or !mcv.isMutable()) return false; diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index 070f41eb5e..ff90c68d42 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -81,6 +81,7 @@ pub const Inst = struct { ref, ret, retvoid, + varptr, /// Write a value to a pointer. LHS is pointer, RHS is value. store, sub, @@ -135,6 +136,7 @@ pub const Inst = struct { .condbr => CondBr, .constant => Constant, .loop => Loop, + .varptr => VarPtr, }; } @@ -434,6 +436,20 @@ pub const Inst = struct { return null; } }; + + pub const VarPtr = struct { + pub const base_tag = Tag.varptr; + + base: Inst, + variable: *Module.Var, + + pub fn operandCount(self: *const VarPtr) usize { + return 0; + } + pub fn getOperand(self: *const VarPtr, index: usize) ?*Inst { + return null; + } + }; }; pub const Body = struct { diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index a6ec90a35b..82671609d0 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -1074,7 +1074,7 @@ pub const Type = extern union { } /// Returns if type can be used for a runtime variable - pub fn isValidVarType(self: Type) bool { + pub fn isValidVarType(self: Type, is_extern: bool) bool { var ty = self; while (true) switch (ty.zigTypeTag()) { .Bool, @@ -1087,6 +1087,7 @@ pub const Type = extern union { .Vector, => return true, + .Opaque => return is_extern, .BoundFn, .ComptimeFloat, .ComptimeInt, @@ -1096,12 +1097,11 @@ pub const Type = extern union { .Void, .Undefined, .Null, - .Opaque, => return false, .Optional => { var buf: Payload.Pointer = undefined; - return ty.optionalChild(&buf).isValidVarType(); + return ty.optionalChild(&buf).isValidVarType(is_extern); }, .Pointer, .Array => ty = ty.elemType(), diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index b6356d9b17..7bebd022ab 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -79,6 +79,7 @@ pub const Value = extern union { int_big_positive, int_big_negative, function, + variable, ref_val, decl_ref, elem_ptr, @@ -196,6 +197,7 @@ pub const Value = extern union { @panic("TODO implement copying of big ints"); }, .function => return self.copyPayloadShallow(allocator, Payload.Function), + .variable => return self.copyPayloadShallow(allocator, Payload.Variable), .ref_val => { const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise); const new_payload = try allocator.create(Payload.RefVal); @@ -310,6 +312,7 @@ pub const Value = extern union { .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}), .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}), .function => return out_stream.writeAll("(function)"), + .variable => return out_stream.writeAll("(variable)"), .ref_val => { const ref_val = val.cast(Payload.RefVal).?; try out_stream.writeAll("&const "); @@ -410,6 +413,7 @@ pub const Value = extern union { .int_big_positive, .int_big_negative, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -471,6 +475,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -548,6 +553,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -625,6 +631,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -728,6 +735,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -810,6 +818,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -974,6 +983,7 @@ pub const Value = extern union { .bool_false, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -1046,6 +1056,7 @@ pub const Value = extern union { .enum_literal_type, .null_value, .function, + .variable, .ref_val, .decl_ref, .elem_ptr, @@ -1182,6 +1193,7 @@ pub const Value = extern union { .bool_false, .null_value, .function, + .variable, .int_u64, .int_i64, .int_big_positive, @@ -1260,6 +1272,7 @@ pub const Value = extern union { .bool_false, .null_value, .function, + .variable, .int_u64, .int_i64, .int_big_positive, @@ -1355,6 +1368,7 @@ pub const Value = extern union { .bool_true, .bool_false, .function, + .variable, .int_u64, .int_i64, .int_big_positive, @@ -1429,6 +1443,11 @@ pub const Value = extern union { func: *Module.Fn, }; + pub const Variable = struct { + base: Payload = Payload{ .tag = .variable }, + variable: *Module.Var, + }; + pub const ArraySentinel0_u8_Type = struct { base: Payload = Payload{ .tag = .array_sentinel_0_u8_type }, len: u64, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 1a2c5cebaa..f59d470ffd 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -1752,6 +1752,9 @@ const EmitZIR = struct { const decl_ref = try self.emitDeclRef(inst.src, declref.decl); try new_body.instructions.append(decl_ref); break :blk decl_ref; + } else if (const_inst.val.cast(Value.Payload.Variable)) |var_pl| blk: { + const owner_decl = var_pl.variable.owner_decl; + break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name)); } else blk: { break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst; }; @@ -2311,6 +2314,8 @@ const EmitZIR = struct { }; break :blk &new_inst.base; }, + + .varptr => @panic("TODO"), }; try self.metadata.put(new_inst, .{ .deaths = inst.deaths }); try instructions.append(new_inst); diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index fb39a1e077..644b73d643 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -366,7 +366,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst. fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { const var_type = try resolveType(mod, scope, inst.positionals.operand); // TODO this should happen only for var allocs - if (!var_type.isValidVarType()) { + if (!var_type.isValidVarType(false)) { return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); } const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); @@ -779,7 +779,7 @@ fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) Inne for (fntype.positionals.param_types) |param_type, i| { const resolved = try resolveType(mod, scope, param_type); // TODO skip for comptime params - if (!resolved.isValidVarType()) { + if (!resolved.isValidVarType(false)) { return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved}); } param_types[i] = resolved; -- cgit v1.2.3 From 9801047bdb26c86da430310aa5d043f6899adbfe Mon Sep 17 00:00:00 2001 From: Vexu Date: Wed, 19 Aug 2020 15:19:00 +0300 Subject: stage2: handle var attributes --- src-self-hosted/Module.zig | 50 +++++++++++++++++++++++++++++++++++--------- src-self-hosted/zir_sema.zig | 1 + 2 files changed, 41 insertions(+), 10 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 3a68063236..8009bcc32d 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -290,6 +290,8 @@ pub const Fn = struct { }, owner_decl: *Decl, + is_pub: bool, + /// This memory is temporary and points to stack memory for the duration /// of Fn analysis. pub const Analysis = struct { @@ -323,7 +325,11 @@ pub const Fn = struct { pub const Var = struct { value: ?Value, owner_decl: *Decl, + + is_pub: bool, + is_extern: bool, is_mutable: bool, + is_threadlocal: bool, }; pub const Scope = struct { @@ -1241,6 +1247,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; defer fn_type_scope.instructions.deinit(self.gpa); + const is_pub = fn_proto.getTrailer("visib_token") != null; const body_node = fn_proto.getTrailer("body_node") orelse return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); @@ -1378,6 +1385,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { new_func.* = .{ .analysis = .{ .queued = fn_zir }, .owner_decl = decl, + .is_pub = is_pub, }; fn_payload.* = .{ .func = new_func }; @@ -1430,13 +1438,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { decl.analysis = .in_progress; - const is_extern = blk: { - const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse - break :blk false; - break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; - }; - const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; - // We need the memory for the Type to go into the arena for the Decl var decl_arena = std.heap.ArenaAllocator.init(self.gpa); errdefer decl_arena.deinit(); @@ -1451,6 +1452,32 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; defer block_scope.instructions.deinit(self.gpa); + const is_pub = var_decl.getTrailer("visib_token") != null; + const is_extern = blk: { + const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse + break :blk false; + break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; + }; + if (var_decl.getTrailer("lib_name")) |lib_name| { + assert(is_extern); + return self.failNode(&block_scope.base, lib_name, "TODO implement function library name", .{}); + } + const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; + const is_threadlocal = if (var_decl.getTrailer("thread_local_token")) |some| blk: { + if (!is_mutable) { + return self.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{}); + } + break :blk true; + } else false; + assert(var_decl.getTrailer("comptime_token") == null); + if (var_decl.getTrailer("align_node")) |align_expr| { + return self.failNode(&block_scope.base, align_expr, "TODO implement function align expression", .{}); + } + if (var_decl.getTrailer("section_node")) |sect_expr| { + return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{}); + } + + const explicit_type = blk: { const type_node = var_decl.getTrailer("type_node") orelse break :blk null; @@ -1543,7 +1570,10 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { new_variable.* = .{ .value = value, .owner_decl = decl, + .is_pub = is_pub, + .is_extern = is_extern, .is_mutable = is_mutable, + .is_threadlocal = is_threadlocal, }; var_payload.* = .{ .variable = new_variable }; @@ -2394,7 +2424,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn const decl_tv = try decl.typedValue(); if (decl_tv.val.tag() == .variable) { - return self.getVarRef(scope, src, decl_tv); + return self.analyzeVarRef(scope, src, decl_tv); } const ty = try self.singlePtrType(scope, src, false, decl_tv.ty); const val_payload = try scope.arena().create(Value.Payload.DeclRef); @@ -2406,11 +2436,11 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn }); } -fn getVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { +fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { const variable = tv.val.cast(Value.Payload.Variable).?.variable; const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); - if (!variable.is_mutable and variable.value != null) { + if (!variable.is_mutable and !variable.is_extern and variable.value != null) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.value.? }; return self.constInst(scope, src, .{ diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index cb1ed08d6d..87cce3adb3 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -666,6 +666,7 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError! new_func.* = .{ .analysis = .{ .queued = fn_zir }, .owner_decl = scope.decl().?, + .is_pub = false, }; const fn_payload = try scope.arena().create(Value.Payload.Function); fn_payload.* = .{ .func = new_func }; -- cgit v1.2.3 From 9ec9c0f5e57820f4baa04b9674a6a4a88235b863 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Aug 2020 17:52:22 -0700 Subject: optimize the memory layout of Module.Fn and Module.Var `is_pub` added to `Fn` would cost us an additional 8 bytes of memory per function, which is a real bummer since it's only 1 bit of information. If we wanted to really remove this, I suspect we could make this a function isPub() which looks at the AST of the corresponding Decl and finds if the FnProto AST node has the pub token. However I saw an easier approach - The data of whether something is pub or not is actually a property of a Decl anyway, not a function, so we can look at moving the field into Decl. Indeed, doing this, we see that Decl already has deletion_flag: bool which is hiding in the padding bytes between the enum (1 byte) and the following u32 field (generation). So if we put the is_pub bool there, it actually will take up no additional space, with 1 byte of padding remaining. This was an easy reworking of the code since any func.is_pub could be changed simply to func.owner_decl.is_pub. I also modified `Var` to make the init value non-optional and moved the optional bit to a has_init: bool field. This is worse from the perspective of control flow and safety, however it makes `@sizeOf(Var)` go from 32 bytes to 24 bytes. The more code we can fit into memory at once, the more justified we are in using the compiler as a long-running process that does incremental updates. --- src-self-hosted/Module.zig | 26 +++++++++++++------------- src-self-hosted/zir.zig | 2 +- src-self-hosted/zir_sema.zig | 1 - test/stage2/compare_output.zig | 2 ++ 4 files changed, 16 insertions(+), 15 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 8009bcc32d..ec69f94e3d 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -170,6 +170,9 @@ pub const Decl = struct { /// This flag is set when this Decl is added to a check_for_deletion set, and cleared /// when removed. deletion_flag: bool, + /// Whether the corresponding AST decl has a `pub` keyword. + is_pub: bool, + /// An integer that can be checked against the corresponding incrementing /// generation field of Module. This is used to determine whether `complete` status /// represents pre- or post- re-analysis. @@ -290,8 +293,6 @@ pub const Fn = struct { }, owner_decl: *Decl, - is_pub: bool, - /// This memory is temporary and points to stack memory for the duration /// of Fn analysis. pub const Analysis = struct { @@ -323,10 +324,10 @@ pub const Fn = struct { }; pub const Var = struct { - value: ?Value, + init: Value, owner_decl: *Decl, - is_pub: bool, + has_init: bool, is_extern: bool, is_mutable: bool, is_threadlocal: bool, @@ -1247,7 +1248,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; defer fn_type_scope.instructions.deinit(self.gpa); - const is_pub = fn_proto.getTrailer("visib_token") != null; + decl.is_pub = fn_proto.getTrailer("visib_token") != null; const body_node = fn_proto.getTrailer("body_node") orelse return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); @@ -1385,7 +1386,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { new_func.* = .{ .analysis = .{ .queued = fn_zir }, .owner_decl = decl, - .is_pub = is_pub, }; fn_payload.* = .{ .func = new_func }; @@ -1452,7 +1452,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { }; defer block_scope.instructions.deinit(self.gpa); - const is_pub = var_decl.getTrailer("visib_token") != null; + decl.is_pub = var_decl.getTrailer("visib_token") != null; const is_extern = blk: { const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse break :blk false; @@ -1477,7 +1477,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{}); } - const explicit_type = blk: { const type_node = var_decl.getTrailer("type_node") orelse break :blk null; @@ -1568,9 +1567,9 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { const new_variable = try decl_arena.allocator.create(Var); const var_payload = try decl_arena.allocator.create(Value.Payload.Variable); new_variable.* = .{ - .value = value, .owner_decl = decl, - .is_pub = is_pub, + .init = value orelse undefined, + .has_init = value != null, .is_extern = is_extern, .is_mutable = is_mutable, .is_threadlocal = is_threadlocal, @@ -2004,6 +2003,7 @@ fn allocateNewDecl( .wasm => .{ .wasm = null }, }, .generation = 0, + .is_pub = false, }; return new_decl; } @@ -2440,15 +2440,15 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner const variable = tv.val.cast(Value.Payload.Variable).?.variable; const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); - if (!variable.is_mutable and !variable.is_extern and variable.value != null) { + if (!variable.is_mutable and !variable.is_extern and variable.has_init) { const val_payload = try scope.arena().create(Value.Payload.RefVal); - val_payload.* = .{ .val = variable.value.? }; + val_payload.* = .{ .val = variable.init }; return self.constInst(scope, src, .{ .ty = ty, .val = Value.initPayload(&val_payload.base), }); } - + const b = try self.requireRuntimeBlock(scope, src); const inst = try b.arena.create(Inst.VarPtr); inst.* = .{ diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 384463caee..552e90956b 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -1881,7 +1881,7 @@ const EmitZIR = struct { } else if (typed_value.val.cast(Value.Payload.Variable)) |variable| { return self.emitTypedValue(src, .{ .ty = typed_value.ty, - .val = variable.variable.value.?, + .val = variable.variable.init, }); } if (typed_value.val.isUndef()) { diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 87cce3adb3..cb1ed08d6d 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -666,7 +666,6 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError! new_func.* = .{ .analysis = .{ .queued = fn_zir }, .owner_decl = scope.decl().?, - .is_pub = false, }; const fn_payload = try scope.arena().create(Value.Payload.Function); fn_payload.* = .{ .func = new_func }; diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 2b8c8e94cc..6fbc760f26 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -586,6 +586,7 @@ pub fn addCases(ctx: *TestContext) !void { "", ); + // Character literals and multiline strings. case.addCompareOutput( \\export fn _start() noreturn { \\ const ignore = @@ -618,6 +619,7 @@ pub fn addCases(ctx: *TestContext) !void { "", ); + // Global const. case.addCompareOutput( \\export fn _start() noreturn { \\ add(aa, bb); -- cgit v1.2.3 From d25674a51ec09640b0140a541a156869b3e03f81 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 11:04:42 +0300 Subject: disallow extern variables with initializers --- lib/std/c/darwin.zig | 2 +- lib/std/special/c.zig | 2 +- lib/std/special/compiler_rt.zig | 2 +- src-self-hosted/Module.zig | 11 +++++++---- src/parser.cpp | 3 +++ test/compile_errors.zig | 6 ++++++ test/standalone/global_linkage/obj1.zig | 4 ++-- test/standalone/global_linkage/obj2.zig | 4 ++-- 8 files changed, 23 insertions(+), 11 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 2426638569..b1f66fa575 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -41,7 +41,7 @@ const mach_hdr = if (@sizeOf(usize) == 8) mach_header_64 else mach_header; /// on this operating system. However when building object files or libraries, /// the system libc won't be linked until the final executable. So we /// export a weak symbol here, to be overridden by the real one. -pub extern "c" var _mh_execute_header: mach_hdr = undefined; +pub extern "c" var _mh_execute_header: mach_hdr; comptime { if (std.Target.current.isDarwin()) { @export(_mh_execute_header, .{ .name = "_mh_execute_header", .linkage = .Weak }); diff --git a/lib/std/special/c.zig b/lib/std/special/c.zig index 170bb98620..8019db9d96 100644 --- a/lib/std/special/c.zig +++ b/lib/std/special/c.zig @@ -35,7 +35,7 @@ comptime { } } -extern var _fltused: c_int = 1; +var _fltused: c_int = 1; extern fn main(argc: c_int, argv: [*:null]?[*:0]u8) c_int; fn wasm_start() callconv(.C) void { diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index 2716de8113..36a731ed5a 100644 --- a/lib/std/special/compiler_rt.zig +++ b/lib/std/special/compiler_rt.zig @@ -335,7 +335,7 @@ fn __stack_chk_fail() callconv(.C) noreturn { @panic("stack smashing detected"); } -extern var __stack_chk_guard: usize = blk: { +var __stack_chk_guard: usize = blk: { var buf = [1]u8{0} ** @sizeOf(usize); buf[@sizeOf(usize) - 1] = 255; buf[@sizeOf(usize) - 2] = '\n'; diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index ec69f94e3d..d08e7f5746 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -324,10 +324,10 @@ pub const Fn = struct { }; pub const Var = struct { + /// if is_extern == true this is undefined init: Value, owner_decl: *Decl, - has_init: bool, is_extern: bool, is_mutable: bool, is_threadlocal: bool, @@ -1456,7 +1456,11 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { const is_extern = blk: { const maybe_extern_token = var_decl.getTrailer("extern_export_token") orelse break :blk false; - break :blk tree.token_ids[maybe_extern_token] == .Keyword_extern; + if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false; + if (var_decl.getTrailer("init_node")) |some| { + return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{}); + } + break :blk true; }; if (var_decl.getTrailer("lib_name")) |lib_name| { assert(is_extern); @@ -1569,7 +1573,6 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { new_variable.* = .{ .owner_decl = decl, .init = value orelse undefined, - .has_init = value != null, .is_extern = is_extern, .is_mutable = is_mutable, .is_threadlocal = is_threadlocal, @@ -2440,7 +2443,7 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner const variable = tv.val.cast(Value.Payload.Variable).?.variable; const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); - if (!variable.is_mutable and !variable.is_extern and variable.has_init) { + if (!variable.is_mutable and !variable.is_extern) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.init }; return self.constInst(scope, src, .{ diff --git a/src/parser.cpp b/src/parser.cpp index 26233ec6a4..1253baf9ea 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -680,6 +680,9 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod, B AstNode *var_decl = ast_parse_var_decl(pc); if (var_decl != nullptr) { assert(var_decl->type == NodeTypeVariableDeclaration); + if (first->id == TokenIdKeywordExtern && var_decl->data.variable_declaration.expr != nullptr) { + ast_error(pc, first, "extern variables have no initializers"); + } var_decl->line = first->start_line; var_decl->column = first->start_column; var_decl->data.variable_declaration.threadlocal_tok = thread_local_kw; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index fd74385d9b..311c5b9319 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,12 @@ const tests = @import("tests.zig"); const std = @import("std"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest("reject extern variables with initializers", + \\extern var foo: int = 2; + , &[_][]const u8{ + "tmp.zig:1:1: error: extern variables have no initializers", + }); + cases.addTest("duplicate/unused labels", \\comptime { \\ blk: { blk: while (false) {} } diff --git a/test/standalone/global_linkage/obj1.zig b/test/standalone/global_linkage/obj1.zig index 95814cda3d..83b66f336b 100644 --- a/test/standalone/global_linkage/obj1.zig +++ b/test/standalone/global_linkage/obj1.zig @@ -1,5 +1,5 @@ -extern var internal_integer: usize = 1; -extern var obj1_integer: usize = 421; +var internal_integer: usize = 1; +var obj1_integer: usize = 421; comptime { @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal }); diff --git a/test/standalone/global_linkage/obj2.zig b/test/standalone/global_linkage/obj2.zig index f2d44b2dc0..2908a627fd 100644 --- a/test/standalone/global_linkage/obj2.zig +++ b/test/standalone/global_linkage/obj2.zig @@ -1,5 +1,5 @@ -extern var internal_integer: usize = 2; -extern var obj2_integer: usize = 422; +var internal_integer: usize = 2; +var obj2_integer: usize = 422; comptime { @export(internal_integer, .{ .name = "internal_integer", .linkage = .Internal }); -- cgit v1.2.3 From ebfe723f3cdbb40d2f2280e223b710418abde777 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 12:20:24 +0300 Subject: stage2: implement rest of simple pointer types --- src-self-hosted/Module.zig | 26 +++++-- src-self-hosted/astgen.zig | 27 +++++-- src-self-hosted/codegen.zig | 2 +- src-self-hosted/type.zig | 181 +++++++++++++++++++++++++++++++++++++------ src-self-hosted/zir.zig | 19 ++++- src-self-hosted/zir_sema.zig | 26 +++---- 6 files changed, 230 insertions(+), 51 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index d08e7f5746..9b27f38fbe 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2429,7 +2429,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn if (decl_tv.val.tag() == .variable) { return self.analyzeVarRef(scope, src, decl_tv); } - const ty = try self.singlePtrType(scope, src, false, decl_tv.ty); + const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One); const val_payload = try scope.arena().create(Value.Payload.DeclRef); val_payload.* = .{ .decl = decl }; @@ -2442,7 +2442,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { const variable = tv.val.cast(Value.Payload.Variable).?.variable; - const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty); + const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty, .One); if (!variable.is_mutable and !variable.is_extern) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.init }; @@ -2766,7 +2766,7 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst // T to ?T if (dest_type.zigTypeTag() == .Optional) { - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; const child_type = dest_type.optionalChild(&buf); if (child_type.eql(inst.ty)) { return self.wrapOptional(scope, dest_type, inst); @@ -3145,10 +3145,20 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: return Value.initPayload(val_payload); } -pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) Allocator.Error!Type { - const type_payload = try scope.arena().create(Type.Payload.Pointer); +pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { + // TODO stage1 type inference bug + const T = Type.Tag; + + const type_payload = try scope.arena().create(Type.Payload.PointerSimple); type_payload.* = .{ - .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer }, + .base = .{ + .tag = switch (size) { + .One => if (mutable) .single_mut_pointer else T.many_const_pointer, + .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, + .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, + else => unreachable, + }, + }, .pointee_type = elem_ty, }; return Type.initPayload(&type_payload.base); @@ -3157,7 +3167,7 @@ pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, el pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { return Type.initPayload(switch (child_type.tag()) { .single_const_pointer => blk: { - const payload = try scope.arena().create(Type.Payload.Pointer); + const payload = try scope.arena().create(Type.Payload.PointerSimple); payload.* = .{ .base = .{ .tag = .optional_single_const_pointer }, .pointee_type = child_type.elemType(), @@ -3165,7 +3175,7 @@ pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Er break :blk &payload.base; }, .single_mut_pointer => blk: { - const payload = try scope.arena().create(Type.Payload.Pointer); + const payload = try scope.arena().create(Type.Payload.PointerSimple); payload.* = .{ .base = .{ .tag = .optional_single_mut_pointer }, .pointee_type = child_type.elemType(), diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 9f8afa6225..bb42b746ad 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -577,6 +577,17 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir .val = Value.initTag(.type_type), }); + const size: std.builtin.TypeInfo.Pointer.Size = switch (tree.token_ids[node.op_token]) { + .Asterisk, .AsteriskAsterisk => .One, + // TODO stage1 type inference bug + .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { + .Identifier => .C, + .RBracket => .Many, + else => unreachable, + }), + else => unreachable, + }; + const simple = node.ptr_info.allowzero_token == null and node.ptr_info.align_info == null and node.ptr_info.volatile_token == null and @@ -584,13 +595,19 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir if (simple) { const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); - return addZIRUnOp(mod, scope, src, if (node.ptr_info.const_token == null) - .single_mut_ptr_type - else - .single_const_ptr_type, child_type); + const mutable = node.ptr_info.const_token == null; + // TODO stage1 type inference bug + const T = zir.Inst.Tag; + return addZIRUnOp(mod, scope, src, switch (size) { + .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, + .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, + .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, + else => unreachable, + }, child_type); } var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{}; + kw_args.size = size; kw_args.@"allowzero" = node.ptr_info.allowzero_token != null; if (node.ptr_info.align_info) |some| { kw_args.@"align" = try expr(mod, scope, .none, some.node); @@ -1271,7 +1288,7 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr i += 1; } const slice = tree.tokenSlice(line); - mem.copy(u8, bytes[i..], slice[2..slice.len - 1]); + mem.copy(u8, bytes[i..], slice[2 .. slice.len - 1]); i += slice.len - 3; } diff --git a/src-self-hosted/codegen.zig b/src-self-hosted/codegen.zig index 1bc76f6b05..cc5c51159c 100644 --- a/src-self-hosted/codegen.zig +++ b/src-self-hosted/codegen.zig @@ -2060,7 +2060,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { if (typed_value.val.isNull()) return MCValue{ .immediate = 0 }; - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; return self.genTypedValue(src, .{ .ty = typed_value.ty.optionalChild(&buf), .val = typed_value.val, diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index c2762e1f8a..233e479297 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -66,10 +66,15 @@ pub const Type = extern union { .function => return .Fn, .array, .array_u8_sentinel_0, .array_u8, .array_sentinel => return .Array, - .single_const_pointer => return .Pointer, - .single_mut_pointer => return .Pointer, - .single_const_pointer_to_comptime_int => return .Pointer, - .const_slice_u8 => return .Pointer, + .single_const_pointer_to_comptime_int, + .const_slice_u8, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + => return .Pointer, .optional, .optional_single_const_pointer, @@ -108,13 +113,17 @@ pub const Type = extern union { return @fieldParentPtr(T, "base", self.ptr_otherwise); } - pub fn castPointer(self: Type) ?*Payload.Pointer { + pub fn castPointer(self: Type) ?*Payload.PointerSimple { return switch (self.tag()) { .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, - => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise), + => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), else => null, }; } @@ -198,8 +207,8 @@ pub const Type = extern union { return true; }, .Optional => { - var buf_a: Payload.Pointer = undefined; - var buf_b: Payload.Pointer = undefined; + var buf_a: Payload.PointerSimple = undefined; + var buf_b: Payload.PointerSimple = undefined; return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b)); }, .Float, @@ -263,7 +272,7 @@ pub const Type = extern union { } }, .Optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; std.hash.autoHash(&hasher, self.optionalChild(&buf).hash()); }, .Float, @@ -374,9 +383,13 @@ pub const Type = extern union { .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"), .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_mut_pointer, .optional_single_const_pointer, - => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"), + => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), } } @@ -482,17 +495,41 @@ pub const Type = extern union { continue; }, .single_const_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("*const "); ty = payload.pointee_type; continue; }, .single_mut_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("*"); ty = payload.pointee_type; continue; }, + .many_const_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*]const "); + ty = payload.pointee_type; + continue; + }, + .many_mut_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*]"); + ty = payload.pointee_type; + continue; + }, + .c_const_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*c]const "); + ty = payload.pointee_type; + continue; + }, + .c_mut_pointer => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[*c]"); + ty = payload.pointee_type; + continue; + }, .int_signed => { const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); return out_stream.print("i{}", .{payload.bits}); @@ -508,13 +545,13 @@ pub const Type = extern union { continue; }, .optional_single_const_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("?*const "); ty = payload.pointee_type; continue; }, .optional_single_mut_pointer => { - const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); try out_stream.writeAll("?*"); ty = payload.pointee_type; continue; @@ -619,6 +656,10 @@ pub const Type = extern union { .array_sentinel => self.elemType().hasCodeGenBits(), .single_const_pointer => self.elemType().hasCodeGenBits(), .single_mut_pointer => self.elemType().hasCodeGenBits(), + .many_const_pointer => self.elemType().hasCodeGenBits(), + .many_mut_pointer => self.elemType().hasCodeGenBits(), + .c_const_pointer => self.elemType().hasCodeGenBits(), + .c_mut_pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -669,6 +710,10 @@ pub const Type = extern union { .const_slice_u8, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -704,7 +749,7 @@ pub const Type = extern union { }, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); if (!child_type.hasCodeGenBits()) return 1; @@ -772,6 +817,10 @@ pub const Type = extern union { .const_slice_u8, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -805,7 +854,7 @@ pub const Type = extern union { }, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); if (!child_type.hasCodeGenBits()) return 1; @@ -872,6 +921,10 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, => false, .single_const_pointer, @@ -922,6 +975,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .fn_noreturn_no_args, .fn_void_no_args, @@ -987,6 +1044,8 @@ pub const Type = extern union { .int_unsigned, .int_signed, .single_mut_pointer, + .many_mut_pointer, + .c_mut_pointer, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, @@ -994,6 +1053,8 @@ pub const Type = extern union { => false, .single_const_pointer, + .many_const_pointer, + .c_const_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, => true, @@ -1048,6 +1109,10 @@ pub const Type = extern union { .int_signed, .single_mut_pointer, .single_const_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1063,7 +1128,7 @@ pub const Type = extern union { switch (self.tag()) { .optional_single_const_pointer, .optional_single_mut_pointer => return true, .optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; const child_type = self.optionalChild(&buf); // optionals of zero sized pointers behave like bools if (!child_type.hasCodeGenBits()) return false; @@ -1101,7 +1166,7 @@ pub const Type = extern union { => return false, .Optional => { - var buf: Payload.Pointer = undefined; + var buf: Payload.PointerSimple = undefined; return ty.optionalChild(&buf).isValidVarType(is_extern); }, .Pointer, .Array => ty = ty.elemType(), @@ -1166,13 +1231,17 @@ pub const Type = extern union { .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, .single_const_pointer => self.castPointer().?.pointee_type, .single_mut_pointer => self.castPointer().?.pointee_type, + .many_const_pointer => self.castPointer().?.pointee_type, + .many_mut_pointer => self.castPointer().?.pointee_type, + .c_const_pointer => self.castPointer().?.pointee_type, + .c_mut_pointer => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), }; } /// Asserts that the type is an optional. - pub fn optionalChild(self: Type, buf: *Payload.Pointer) Type { + pub fn optionalChild(self: Type, buf: *Payload.PointerSimple) Type { return switch (self.tag()) { .optional => self.cast(Payload.Optional).?.child_type, .optional_single_mut_pointer => { @@ -1199,7 +1268,7 @@ pub const Type = extern union { return switch (self.tag()) { .optional => self.cast(Payload.Optional).?.child_type, .optional_single_mut_pointer, .optional_single_const_pointer => { - const payload = try allocator.create(Payload.Pointer); + const payload = try allocator.create(Payload.PointerSimple); payload.* = .{ .base = .{ .tag = if (self.tag() == .optional_single_const_pointer) @@ -1258,6 +1327,10 @@ pub const Type = extern union { .function, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1318,6 +1391,10 @@ pub const Type = extern union { .function, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1368,6 +1445,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1429,6 +1510,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_signed, @@ -1490,6 +1575,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1549,6 +1638,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1637,6 +1730,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1701,6 +1798,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1764,6 +1865,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1827,6 +1932,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1887,6 +1996,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1947,6 +2060,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2027,6 +2144,10 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -2109,7 +2230,13 @@ pub const Type = extern union { ty = ty.elemType(); continue; }, - .single_const_pointer, .single_mut_pointer => { + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .single_const_pointer, + .single_mut_pointer, + => { const ptr = ty.castPointer().?; ty = ptr.pointee_type; continue; @@ -2167,11 +2294,17 @@ pub const Type = extern union { .array_u8_sentinel_0, .single_const_pointer, .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, => return false, + + .c_const_pointer, + .c_mut_pointer, + => return true, }; } @@ -2231,6 +2364,10 @@ pub const Type = extern union { array_sentinel, single_const_pointer, single_mut_pointer, + many_const_pointer, + many_mut_pointer, + c_const_pointer, + c_mut_pointer, int_signed, int_unsigned, function, @@ -2272,7 +2409,7 @@ pub const Type = extern union { elem_type: Type, }; - pub const Pointer = struct { + pub const PointerSimple = struct { base: Payload, pointee_type: Type, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 552e90956b..62c0c73f3f 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -198,6 +198,14 @@ pub const Inst = struct { single_const_ptr_type, /// Create a mutable pointer type based on the element type. `*T` single_mut_ptr_type, + /// Create a const pointer type based on the element type. `[*]const T` + many_const_ptr_type, + /// Create a mutable pointer type based on the element type. `[*]T` + many_mut_ptr_type, + /// Create a const pointer type based on the element type. `[*c]const T` + c_const_ptr_type, + /// Create a mutable pointer type based on the element type. `[*c]T` + c_mut_ptr_type, /// Create a pointer type with attributes ptr_type, /// Write a value to a pointer. For loading, see `deref`. @@ -262,6 +270,10 @@ pub const Inst = struct { .typeof, .single_const_ptr_type, .single_mut_ptr_type, + .many_const_ptr_type, + .many_mut_ptr_type, + .c_const_ptr_type, + .c_mut_ptr_type, .optional_type, .unwrap_optional_safe, .unwrap_optional_unsafe, @@ -400,6 +412,10 @@ pub const Inst = struct { .shr, .single_const_ptr_type, .single_mut_ptr_type, + .many_const_ptr_type, + .many_mut_ptr_type, + .c_const_ptr_type, + .c_mut_ptr_type, .store, .str, .sub, @@ -859,6 +875,7 @@ pub const Inst = struct { @"const": bool = true, @"volatile": bool = false, sentinel: ?*Inst = null, + size: std.builtin.TypeInfo.Pointer.Size = .One, }, }; @@ -2443,7 +2460,7 @@ const EmitZIR = struct { } }, .Optional => { - var buf: Type.Payload.Pointer = undefined; + var buf: Type.Payload.PointerSimple = undefined; const inst = try self.arena.allocator.create(Inst.UnOp); inst.* = .{ .base = .{ diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index cb1ed08d6d..0e331d1979 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -51,8 +51,12 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?), .ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?), .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?), - .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?), - .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?), + .single_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One), + .single_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One), + .many_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many), + .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), + .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), + .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), @@ -324,7 +328,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { const operand = try resolveInst(mod, scope, inst.positionals.operand); - const ptr_type = try mod.singlePtrType(scope, inst.base.src, false, operand.ty); + const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One); if (operand.value()) |val| { const ref_payload = try scope.arena().create(Value.Payload.RefVal); @@ -369,7 +373,7 @@ fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerErro if (!var_type.isValidVarType(false)) { return mod.fail(scope, inst.base.src, "variable of type '{}' must be const or comptime", .{var_type}); } - const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type); + const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One); const b = try mod.requireRuntimeBlock(scope, inst.base.src); return mod.addNoOp(b, inst.base.src, ptr_type, .alloc); } @@ -723,7 +727,7 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp } const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena()); - const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type); + const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, operand.ty.isConstPtr(), .One); if (operand.value()) |val| { if (val.isNull()) { @@ -940,7 +944,7 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne // required a larger index. const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64)); - const type_payload = try scope.arena().create(Type.Payload.Pointer); + const type_payload = try scope.arena().create(Type.Payload.PointerSimple); type_payload.* = .{ .base = .{ .tag = .single_const_pointer }, .pointee_type = array_ptr.ty.elemType().elemType(), @@ -1311,15 +1315,9 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr return decl; } -fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { +fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst { const elem_type = try resolveType(mod, scope, inst.positionals.operand); - const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type); - return mod.constType(scope, inst.base.src, ty); -} - -fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { - const elem_type = try resolveType(mod, scope, inst.positionals.operand); - const ty = try mod.singlePtrType(scope, inst.base.src, true, elem_type); + const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size); return mod.constType(scope, inst.base.src, ty); } -- cgit v1.2.3 From 95682484503f031efefb2c085cdd4d0b64cf8795 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 13:52:18 +0300 Subject: stage2: complex pointer types --- src-self-hosted/Module.zig | 34 +++++++++++- src-self-hosted/astgen.zig | 5 +- src-self-hosted/type.zig | 126 ++++++++++++++++++++++++++++++++++++++++--- src-self-hosted/zir.zig | 2 +- src-self-hosted/zir_sema.zig | 47 +++++++++++++++- 5 files changed, 202 insertions(+), 12 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 9b27f38fbe..2dd64c64bc 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -3153,7 +3153,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu type_payload.* = .{ .base = .{ .tag = switch (size) { - .One => if (mutable) .single_mut_pointer else T.many_const_pointer, + .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, else => unreachable, @@ -3164,6 +3164,38 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu return Type.initPayload(&type_payload.base); } +pub fn ptrType( + self: *Module, + scope: *Scope, + src: usize, + elem_ty: Type, + sentinel: ?Value, + @"align": u32, + bit_offset: u16, + host_size: u16, + mutable: bool, + @"allowzero": bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, +) Allocator.Error!Type { + assert(host_size == 0 or bit_offset < host_size * 8); + + // TODO check if type can be represented by simplePtrType + const type_payload = try scope.arena().create(Type.Payload.Pointer); + type_payload.* = .{ + .pointee_type = elem_ty, + .sentinel = sentinel, + .@"align" = @"align", + .bit_offset = bit_offset, + .host_size = host_size, + .@"allowzero" = @"allowzero", + .mutable = mutable, + .@"volatile" = @"volatile", + .size = size, + }; + return Type.initPayload(&type_payload.base); +} + pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type { return Type.initPayload(switch (child_type.tag()) { .single_const_pointer => blk: { diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index bb42b746ad..832e6848b3 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -582,8 +582,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir // TODO stage1 type inference bug .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { .Identifier => .C, - .RBracket => .Many, - else => unreachable, + else => .Many, }), else => unreachable, }; @@ -616,7 +615,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); } } - kw_args.@"const" = node.ptr_info.const_token != null; + kw_args.mutable = node.ptr_info.const_token == null; kw_args.@"volatile" = node.ptr_info.volatile_token != null; if (node.ptr_info.sentinel) |some| { kw_args.sentinel = try expr(mod, scope, .none, some); diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 233e479297..2c326b9308 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -74,6 +74,7 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .pointer, => return .Pointer, .optional, @@ -390,6 +391,25 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + const new_payload = try allocator.create(Payload.Pointer); + new_payload.* = .{ + .base = payload.base, + + .pointee_type = try payload.pointee_type.copy(allocator), + .sentinel = if (payload.sentinel) |some| try some.copy(allocator) else null, + .@"align" = payload.@"align", + .bit_offset = payload.bit_offset, + .host_size = payload.host_size, + .@"allowzero" = payload.@"allowzero", + .mutable = payload.mutable, + .@"volatile" = payload.@"volatile", + .size = payload.size, + }; + return Type{ .ptr_otherwise = &new_payload.base }; + }, } } @@ -556,6 +576,34 @@ pub const Type = extern union { ty = payload.pointee_type; continue; }, + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise); + if (payload.sentinel) |some| switch (payload.size) { + .One, .C => unreachable, + .Many => try out_stream.writeAll("[*:{}]"), + .Slice => try out_stream.writeAll("[:{}]"), + } else switch (payload.size) { + .One => try out_stream.writeAll("*"), + .Many => try out_stream.writeAll("[*]"), + .C => try out_stream.writeAll("[*c]"), + .Slice => try out_stream.writeAll("[]"), + } + if (payload.@"align" != 0) { + try out_stream.print("align({}", .{payload.@"align"}); + + if (payload.bit_offset != 0) { + try out_stream.print(":{}:{}", .{ payload.bit_offset, payload.host_size }); + } + try out_stream.writeAll(") "); + } + if (!payload.mutable) try out_stream.writeAll("const "); + if (payload.@"volatile") try out_stream.writeAll("volatile "); + if (payload.@"allowzero") try out_stream.writeAll("allowzero "); + + ty = payload.pointee_type; + continue; + }, } unreachable; } @@ -660,6 +708,7 @@ pub const Type = extern union { .many_mut_pointer => self.elemType().hasCodeGenBits(), .c_const_pointer => self.elemType().hasCodeGenBits(), .c_mut_pointer => self.elemType().hasCodeGenBits(), + .pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -718,6 +767,13 @@ pub const Type = extern union { .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + + if (payload.@"align" != 0) return payload.@"align"; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, + .c_short => return @divExact(CType.short.sizeInBits(target), 8), .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), .c_int => return @divExact(CType.int.sizeInBits(target), 8), @@ -789,6 +845,7 @@ pub const Type = extern union { .@"null" => unreachable, .@"undefined" => unreachable, .enum_literal => unreachable, + .single_const_pointer_to_comptime_int => unreachable, .u8, .i8, @@ -812,18 +869,28 @@ pub const Type = extern union { .i64, .u64 => return 8, .isize, - .usize, - .single_const_pointer_to_comptime_int, - .const_slice_u8, + .usize + => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, + + .optional_single_const_pointer, + .optional_single_mut_pointer, + => { + if (self.elemType().hasCodeGenBits()) return 1; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, + .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, - .optional_single_const_pointer, - .optional_single_mut_pointer, - => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + .pointer, + => { + if (self.elemType().hasCodeGenBits()) return 0; + return @divExact(target.cpu.arch.ptrBitWidth(), 8); + }, .c_short => return @divExact(CType.short.sizeInBits(target), 8), .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8), @@ -931,6 +998,8 @@ pub const Type = extern union { .single_mut_pointer, .single_const_pointer_to_comptime_int, => true, + + .pointer => self.cast(Payload.Pointer).?.size == .One, }; } @@ -994,6 +1063,8 @@ pub const Type = extern union { => false, .const_slice_u8 => true, + + .pointer => self.cast(Payload.Pointer).?.size == .Slice, }; } @@ -1058,6 +1129,8 @@ pub const Type = extern union { .single_const_pointer_to_comptime_int, .const_slice_u8, => true, + + .pointer => !self.cast(Payload.Pointer).?.mutable, }; } @@ -1120,6 +1193,11 @@ pub const Type = extern union { .optional_single_const_pointer, .enum_literal, => false, + + .pointer => { + const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise); + return payload.@"volatile"; + }, }; } @@ -1237,6 +1315,7 @@ pub const Type = extern union { .c_mut_pointer => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), + .pointer => self.cast(Payload.Pointer).?.pointee_type, }; } @@ -1325,6 +1404,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, .function, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1389,6 +1469,7 @@ pub const Type = extern union { .fn_naked_noreturn_no_args, .fn_ccc_void_no_args, .function, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1443,6 +1524,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1508,6 +1590,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1573,6 +1656,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1636,6 +1720,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1728,6 +1813,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1796,6 +1882,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1863,6 +1950,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1930,6 +2018,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -1994,6 +2083,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2058,6 +2148,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2142,6 +2233,7 @@ pub const Type = extern union { .array_sentinel, .array_u8, .array_u8_sentinel_0, + .pointer, .single_const_pointer, .single_mut_pointer, .many_const_pointer, @@ -2241,6 +2333,10 @@ pub const Type = extern union { ty = ptr.pointee_type; continue; }, + .pointer => { + ty = ty.cast(Payload.Pointer).?.pointee_type; + continue; + }, }; } @@ -2305,6 +2401,8 @@ pub const Type = extern union { .c_const_pointer, .c_mut_pointer, => return true, + + .pointer => self.cast(Payload.Pointer).?.size == .C, }; } @@ -2362,6 +2460,7 @@ pub const Type = extern union { array_u8_sentinel_0, array, array_sentinel, + pointer, single_const_pointer, single_mut_pointer, many_const_pointer, @@ -2440,6 +2539,21 @@ pub const Type = extern union { child_type: Type, }; + + pub const Pointer = struct { + base: Payload = .{ .tag = .pointer }, + + pointee_type: Type, + sentinel: ?Value, + /// If zero use pointee_type.AbiAlign() + @"align": u32, + bit_offset: u16, + host_size: u16, + @"allowzero": bool, + mutable: bool, + @"volatile": bool, + size: std.builtin.TypeInfo.Pointer.Size, + }; }; }; diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index 62c0c73f3f..db0ec242cc 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -872,7 +872,7 @@ pub const Inst = struct { @"align": ?*Inst = null, align_bit_start: ?*Inst = null, align_bit_end: ?*Inst = null, - @"const": bool = true, + mutable: bool = true, @"volatile": bool = false, sentinel: ?*Inst = null, size: std.builtin.TypeInfo.Pointer.Size = .One, diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index 0e331d1979..ea3b85b29a 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -271,6 +271,14 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type { return val.toType(); } +fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 { + const new_inst = try resolveInst(mod, scope, old_inst); + const coerced = try mod.coerce(scope, dest_type, new_inst); + const val = try mod.resolveConstValue(scope, coerced); + + return val.toUnsignedInt(); +} + pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue { const new_inst = try resolveInst(mod, scope, old_inst); const val = try mod.resolveConstValue(scope, new_inst); @@ -1322,5 +1330,42 @@ fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, m } fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst { - return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{}); + // TODO lazy values + const @"align" = if (inst.kw_args.@"align") |some| + @truncate(u32, try resolveInt(mod, scope, some, Type.initTag(.u32))) + else + 0; + const bit_offset = if (inst.kw_args.align_bit_start) |some| + @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) + else + 0; + const host_size = if (inst.kw_args.align_bit_end) |some| + @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16))) + else + 0; + + if (host_size != 0 and bit_offset >= host_size * 8) + return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{}); + + const sentinel = if (inst.kw_args.sentinel) |some| + (try resolveInstConst(mod, scope, some)).val + else + null; + + const elem_type = try resolveType(mod, scope, inst.positionals.child_type); + + const ty = try mod.ptrType( + scope, + inst.base.src, + elem_type, + sentinel, + @"align", + bit_offset, + host_size, + inst.kw_args.mutable, + inst.kw_args.@"allowzero", + inst.kw_args.@"volatile", + inst.kw_args.size, + ); + return mod.constType(scope, inst.base.src, ty); } -- cgit v1.2.3 From d312d64c9aa058293d69b2bf97c51f4caa7a2d9d Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 16:37:28 +0300 Subject: stage2: slice types --- src-self-hosted/Module.zig | 5 ++- src-self-hosted/astgen.zig | 50 +++++++++++++---------- src-self-hosted/type.zig | 97 +++++++++++++++++++++++++++++++++++--------- src-self-hosted/zir.zig | 20 ++++++--- src-self-hosted/zir_sema.zig | 2 + 5 files changed, 127 insertions(+), 47 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 2dd64c64bc..4893aaba7a 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -3146,6 +3146,9 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: } pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { + if (size == .Slice and elem_ty.eql(Type.initTag(.u8))) { + return Type.initTag(.const_slice_u8); + } // TODO stage1 type inference bug const T = Type.Tag; @@ -3156,7 +3159,7 @@ pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mu .One => if (mutable) T.single_mut_pointer else T.single_const_pointer, .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer, .C => if (mutable) T.c_mut_pointer else T.c_const_pointer, - else => unreachable, + .Slice => if (mutable) T.mut_slice else T.const_slice, }, }, .pointee_type = elem_ty, diff --git a/src-self-hosted/astgen.zig b/src-self-hosted/astgen.zig index 832e6848b3..8276b191cb 100644 --- a/src-self-hosted/astgen.zig +++ b/src-self-hosted/astgen.zig @@ -262,6 +262,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .EnumLiteral => return rlWrap(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), .MultilineStringLiteral => return rlWrap(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), .CharLiteral => return rlWrap(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), + .SliceType => return rlWrap(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)), .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}), @@ -275,7 +276,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .NegationWrap => return mod.failNode(scope, node, "TODO implement astgen.expr for .NegationWrap", .{}), .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), - .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}), .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}), .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}), .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), @@ -569,15 +569,16 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn return addZIRUnOp(mod, scope, src, .optional_type, operand); } -fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst { +fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.SliceType) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.op_token].start; - const meta_type = try addZIRInstConst(mod, scope, src, .{ - .ty = Type.initTag(.type), - .val = Value.initTag(.type_type), - }); + return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice); +} - const size: std.builtin.TypeInfo.Pointer.Size = switch (tree.token_ids[node.op_token]) { +fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst { + const tree = scope.tree(); + const src = tree.token_locs[node.op_token].start; + return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, switch (tree.token_ids[node.op_token]) { .Asterisk, .AsteriskAsterisk => .One, // TODO stage1 type inference bug .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { @@ -585,43 +586,50 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir else => .Many, }), else => unreachable, - }; + }); +} - const simple = node.ptr_info.allowzero_token == null and - node.ptr_info.align_info == null and - node.ptr_info.volatile_token == null and - node.ptr_info.sentinel == null; +fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, rhs: *ast.Node, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*zir.Inst { + const meta_type = try addZIRInstConst(mod, scope, src, .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.type_type), + }); + + const simple = ptr_info.allowzero_token == null and + ptr_info.align_info == null and + ptr_info.volatile_token == null and + ptr_info.sentinel == null; if (simple) { - const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); - const mutable = node.ptr_info.const_token == null; + const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); + const mutable = ptr_info.const_token == null; // TODO stage1 type inference bug const T = zir.Inst.Tag; return addZIRUnOp(mod, scope, src, switch (size) { .One => if (mutable) T.single_mut_ptr_type else T.single_const_ptr_type, .Many => if (mutable) T.many_mut_ptr_type else T.many_const_ptr_type, .C => if (mutable) T.c_mut_ptr_type else T.c_const_ptr_type, - else => unreachable, + .Slice => if (mutable) T.mut_slice_type else T.mut_slice_type, }, child_type); } var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{}; kw_args.size = size; - kw_args.@"allowzero" = node.ptr_info.allowzero_token != null; - if (node.ptr_info.align_info) |some| { + kw_args.@"allowzero" = ptr_info.allowzero_token != null; + if (ptr_info.align_info) |some| { kw_args.@"align" = try expr(mod, scope, .none, some.node); if (some.bit_range) |bit_range| { kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start); kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end); } } - kw_args.mutable = node.ptr_info.const_token == null; - kw_args.@"volatile" = node.ptr_info.volatile_token != null; - if (node.ptr_info.sentinel) |some| { + kw_args.mutable = ptr_info.const_token == null; + kw_args.@"volatile" = ptr_info.volatile_token != null; + if (ptr_info.sentinel) |some| { kw_args.sentinel = try expr(mod, scope, .none, some); } - const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); + const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs); if (kw_args.sentinel) |some| { kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some); } diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 2c326b9308..2218c49200 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -74,6 +74,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .pointer, => return .Pointer, @@ -122,6 +124,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, => @fieldParentPtr(Payload.PointerSimple, "base", self.ptr_otherwise), @@ -388,6 +392,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_mut_pointer, .optional_single_const_pointer, => return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"), @@ -550,6 +556,18 @@ pub const Type = extern union { ty = payload.pointee_type; continue; }, + .const_slice => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[]const "); + ty = payload.pointee_type; + continue; + }, + .mut_slice => { + const payload = @fieldParentPtr(Payload.PointerSimple, "base", ty.ptr_otherwise); + try out_stream.writeAll("[]"); + ty = payload.pointee_type; + continue; + }, .int_signed => { const payload = @fieldParentPtr(Payload.IntSigned, "base", ty.ptr_otherwise); return out_stream.print("i{}", .{payload.bits}); @@ -701,14 +719,7 @@ pub const Type = extern union { // TODO lazy types .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, .array_u8 => self.arrayLen() != 0, - .array_sentinel => self.elemType().hasCodeGenBits(), - .single_const_pointer => self.elemType().hasCodeGenBits(), - .single_mut_pointer => self.elemType().hasCodeGenBits(), - .many_const_pointer => self.elemType().hasCodeGenBits(), - .many_mut_pointer => self.elemType().hasCodeGenBits(), - .c_const_pointer => self.elemType().hasCodeGenBits(), - .c_mut_pointer => self.elemType().hasCodeGenBits(), - .pointer => self.elemType().hasCodeGenBits(), + .array_sentinel, .single_const_pointer, .single_mut_pointer, .many_const_pointer, .many_mut_pointer, .c_const_pointer, .c_mut_pointer, .const_slice, .mut_slice, .pointer => self.elemType().hasCodeGenBits(), .int_signed => self.cast(Payload.IntSigned).?.bits == 0, .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, @@ -763,6 +774,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .optional_single_const_pointer, .optional_single_mut_pointer, => return @divExact(target.cpu.arch.ptrBitWidth(), 8), @@ -868,10 +881,12 @@ pub const Type = extern union { .i32, .u32 => return 4, .i64, .u64 => return 8, - .isize, - .usize - => return @divExact(target.cpu.arch.ptrBitWidth(), 8), - .const_slice_u8 => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, + .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8), + + .const_slice, + .mut_slice, + .const_slice_u8, + => return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2, .optional_single_const_pointer, .optional_single_mut_pointer, @@ -992,6 +1007,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, => false, .single_const_pointer, @@ -1062,7 +1079,10 @@ pub const Type = extern union { .enum_literal, => false, - .const_slice_u8 => true, + .const_slice, + .mut_slice, + .const_slice_u8, + => true, .pointer => self.cast(Payload.Pointer).?.size == .Slice, }; @@ -1121,6 +1141,7 @@ pub const Type = extern union { .optional_single_mut_pointer, .optional_single_const_pointer, .enum_literal, + .mut_slice, => false, .single_const_pointer, @@ -1128,6 +1149,7 @@ pub const Type = extern union { .c_const_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, + .const_slice, => true, .pointer => !self.cast(Payload.Pointer).?.mutable, @@ -1186,6 +1208,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1307,12 +1331,15 @@ pub const Type = extern union { .array => self.cast(Payload.Array).?.elem_type, .array_sentinel => self.cast(Payload.ArraySentinel).?.elem_type, - .single_const_pointer => self.castPointer().?.pointee_type, - .single_mut_pointer => self.castPointer().?.pointee_type, - .many_const_pointer => self.castPointer().?.pointee_type, - .many_mut_pointer => self.castPointer().?.pointee_type, - .c_const_pointer => self.castPointer().?.pointee_type, - .c_mut_pointer => self.castPointer().?.pointee_type, + .single_const_pointer, + .single_mut_pointer, + .many_const_pointer, + .many_mut_pointer, + .c_const_pointer, + .c_mut_pointer, + .const_slice, + .mut_slice, + => self.castPointer().?.pointee_type, .array_u8, .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8), .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), .pointer => self.cast(Payload.Pointer).?.pointee_type, @@ -1411,6 +1438,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1476,6 +1505,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1531,6 +1562,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1597,6 +1630,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_signed, @@ -1663,6 +1698,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -1727,6 +1764,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .int_unsigned, @@ -1820,6 +1859,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1889,6 +1930,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -1957,6 +2000,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2025,6 +2070,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2090,6 +2137,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2155,6 +2204,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .u8, @@ -2240,6 +2291,8 @@ pub const Type = extern union { .many_mut_pointer, .c_const_pointer, .c_mut_pointer, + .const_slice, + .mut_slice, .single_const_pointer_to_comptime_int, .const_slice_u8, .optional, @@ -2290,6 +2343,8 @@ pub const Type = extern union { .array_sentinel, .array_u8_sentinel_0, .const_slice_u8, + .const_slice, + .mut_slice, .c_void, .optional, .optional_single_mut_pointer, @@ -2392,6 +2447,8 @@ pub const Type = extern union { .single_mut_pointer, .many_const_pointer, .many_mut_pointer, + .const_slice, + .mut_slice, .optional, .optional_single_mut_pointer, .optional_single_const_pointer, @@ -2467,6 +2524,8 @@ pub const Type = extern union { many_mut_pointer, c_const_pointer, c_mut_pointer, + const_slice, + mut_slice, int_signed, int_unsigned, function, diff --git a/src-self-hosted/zir.zig b/src-self-hosted/zir.zig index db0ec242cc..a3ea1f11ab 100644 --- a/src-self-hosted/zir.zig +++ b/src-self-hosted/zir.zig @@ -194,18 +194,22 @@ pub const Inst = struct { shl, /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type. shr, - /// Create a const pointer type based on the element type. `*const T` + /// Create a const pointer type with element type T. `*const T` single_const_ptr_type, - /// Create a mutable pointer type based on the element type. `*T` + /// Create a mutable pointer type with element type T. `*T` single_mut_ptr_type, - /// Create a const pointer type based on the element type. `[*]const T` + /// Create a const pointer type with element type T. `[*]const T` many_const_ptr_type, - /// Create a mutable pointer type based on the element type. `[*]T` + /// Create a mutable pointer type with element type T. `[*]T` many_mut_ptr_type, - /// Create a const pointer type based on the element type. `[*c]const T` + /// Create a const pointer type with element type T. `[*c]const T` c_const_ptr_type, - /// Create a mutable pointer type based on the element type. `[*c]T` + /// Create a mutable pointer type with element type T. `[*c]T` c_mut_ptr_type, + /// Create a mutable slice type with element type T. `[]T` + mut_slice_type, + /// Create a const slice type with element type T. `[]T` + const_slice_type, /// Create a pointer type with attributes ptr_type, /// Write a value to a pointer. For loading, see `deref`. @@ -274,6 +278,8 @@ pub const Inst = struct { .many_mut_ptr_type, .c_const_ptr_type, .c_mut_ptr_type, + .mut_slice_type, + .const_slice_type, .optional_type, .unwrap_optional_safe, .unwrap_optional_unsafe, @@ -416,6 +422,8 @@ pub const Inst = struct { .many_mut_ptr_type, .c_const_ptr_type, .c_mut_ptr_type, + .mut_slice_type, + .const_slice_type, .store, .str, .sub, diff --git a/src-self-hosted/zir_sema.zig b/src-self-hosted/zir_sema.zig index ea3b85b29a..75ec7f6306 100644 --- a/src-self-hosted/zir_sema.zig +++ b/src-self-hosted/zir_sema.zig @@ -57,6 +57,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! .many_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many), .c_const_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C), .c_mut_ptr_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C), + .const_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice), + .mut_slice_type => return analyzeInstSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice), .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?), .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?), .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?), -- cgit v1.2.3 From 6a053ffcc85ce3f2b598be08e5d0587c930b4358 Mon Sep 17 00:00:00 2001 From: Vexu Date: Thu, 20 Aug 2020 18:50:13 +0300 Subject: stage2: comptime decl --- src-self-hosted/Module.zig | 51 +++++++++++++++++++++++++++++++++++++++--- test/stage2/compare_output.zig | 5 ----- test/stage2/compile_errors.zig | 36 ++++++++++------------------- 3 files changed, 60 insertions(+), 32 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 4893aaba7a..ba39aa8f38 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -1485,6 +1485,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { const type_node = var_decl.getTrailer("type_node") orelse break :blk null; + // Temporary arena for the zir instructions. var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); defer type_scope_arena.deinit(); var type_scope: Scope.GenZIR = .{ @@ -1539,7 +1540,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { try self.coerce(&inner_block.base, some, ret.operand) else ret.operand; - const val = try self.resolveConstValue(&inner_block.base, coerced); + const val = coerced.value() orelse + return self.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{}); var_type = explicit_type orelse try ret.operand.ty.copy(block_scope.arena); break :blk try val.copy(block_scope.arena); @@ -1603,7 +1605,41 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool { } return type_changed; }, - .Comptime => @panic("TODO comptime decl"), + .Comptime => { + const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node); + + decl.analysis = .in_progress; + + // A comptime decl does not store any value so we can just deinit this arena after analysis is done. + var analysis_arena = std.heap.ArenaAllocator.init(self.gpa); + defer analysis_arena.deinit(); + var gen_scope: Scope.GenZIR = .{ + .decl = decl, + .arena = &analysis_arena.allocator, + .parent = decl.scope, + }; + defer gen_scope.instructions.deinit(self.gpa); + + // TODO comptime scope here + _ = try astgen.expr(self, &gen_scope.base, .none, comptime_decl.expr); + + var block_scope: Scope.Block = .{ + .parent = null, + .func = null, + .decl = decl, + .instructions = .{}, + .arena = &analysis_arena.allocator, + }; + defer block_scope.instructions.deinit(self.gpa); + + _ = try zir_sema.analyzeBody(self, &block_scope.base, .{ + .instructions = gen_scope.instructions.items, + }); + + decl.analysis = .complete; + decl.generation = self.generation; + return true; + }, .Use => @panic("TODO usingnamespace decl"), else => unreachable, } @@ -1794,7 +1830,16 @@ fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { } } } else if (src_decl.castTag(.Comptime)) |comptime_node| { - log.err("TODO: analyze comptime decl", .{}); + const name_index = self.getNextAnonNameIndex(); + const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index}); + defer self.gpa.free(name); + + const name_hash = root_scope.fullyQualifiedNameHash(name); + const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl)); + + const new_decl = try self.createNewDecl(&root_scope.base, name, decl_i, name_hash, contents_hash); + root_scope.decls.appendAssumeCapacity(new_decl); + self.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); } else if (src_decl.castTag(.ContainerField)) |container_field| { log.err("TODO: analyze container field", .{}); } else if (src_decl.castTag(.TestDecl)) |test_decl| { diff --git a/test/stage2/compare_output.zig b/test/stage2/compare_output.zig index 6fbc760f26..6c4b9c47e0 100644 --- a/test/stage2/compare_output.zig +++ b/test/stage2/compare_output.zig @@ -23,11 +23,6 @@ pub fn addCases(ctx: *TestContext) !void { case.addError("", &[_][]const u8{":1:1: error: no entry point found"}); - case.addError( - \\export fn _start() noreturn { - \\} - , &[_][]const u8{":2:1: error: expected noreturn, found void"}); - // Regular old hello world case.addCompareOutput( \\export fn _start() noreturn { diff --git a/test/stage2/compile_errors.zig b/test/stage2/compile_errors.zig index 45e60c0741..d90c0c7fae 100644 --- a/test/stage2/compile_errors.zig +++ b/test/stage2/compile_errors.zig @@ -67,6 +67,18 @@ pub fn addCases(ctx: *TestContext) !void { \\fn entry() void {} , &[_][]const u8{":2:4: error: redefinition of 'entry'"}); + ctx.compileError("incorrect return type", linux_x64, + \\export fn _start() noreturn { + \\} + , &[_][]const u8{":2:1: error: expected noreturn, found void"}); + + ctx.compileError("extern variable has no type", linux_x64, + \\comptime { + \\ _ = foo; + \\} + \\extern var foo; + , &[_][]const u8{":4:1: error: unable to infer variable type"}); + //ctx.incrementalFailure("function redefinition", linux_x64, // \\fn entry() void {} // \\fn entry() void {} @@ -108,28 +120,4 @@ pub fn addCases(ctx: *TestContext) !void { // \\ return 36893488147419103232; // \\} //, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'"); - - //ctx.testCompileError( - // \\comptime { - // \\ var a: *align(4) align(4) i32 = 0; - // \\} - //, "1.zig", 2, 22, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var b: *const const i32 = 0; - // \\} - //, "1.zig", 2, 19, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var c: *volatile volatile i32 = 0; - // \\} - //, "1.zig", 2, 22, "Extra align qualifier"); - - //ctx.testCompileError( - // \\comptime { - // \\ var d: *allowzero allowzero i32 = 0; - // \\} - //, "1.zig", 2, 23, "Extra align qualifier"); } -- cgit v1.2.3 From f54b2e2da6a9ef72a37fae064dc04d951c686298 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Aug 2020 17:08:01 -0700 Subject: add missing mutability check in simplePtrType --- src-self-hosted/Module.zig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src-self-hosted/Module.zig') diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index ba39aa8f38..c0d1d0d654 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2487,7 +2487,7 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst { const variable = tv.val.cast(Value.Payload.Variable).?.variable; - const ty = try self.singlePtrType(scope, src, variable.is_mutable, tv.ty, .One); + const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One); if (!variable.is_mutable and !variable.is_extern) { const val_payload = try scope.arena().create(Value.Payload.RefVal); val_payload.* = .{ .val = variable.init }; @@ -3191,7 +3191,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: } pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type { - if (size == .Slice and elem_ty.eql(Type.initTag(.u8))) { + if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) { return Type.initTag(.const_slice_u8); } // TODO stage1 type inference bug -- cgit v1.2.3