authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-23 20:19:05+03:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-24 15:36:42-07:00
log1520e084cb5fee08ddaf670046c38fd34d3d2cff
treea87a0d1f866186495f9347c0b1a201310da175c9
parente9b15ac9a099fd17e6b68d0f04ec42a2dbfda0ca

stage2: implement accessing error values


4 files changed, 96 insertions(+), 33 deletions(-)

src-self-hosted/Module.zig+7-4
......@@ -2081,12 +2081,15 @@ fn createNewDecl(
20812081}
20822082
20832083/// Get error value for error tag `name`.
2084pub fn getErrorValue(self: *Module, name: []const u8) !u16 {
2084pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {
20852085 const new_val = @intCast(u16, self.global_error_set.items().len);
2086 if (self.global_error_set.get(name)) |some| return some;
2086 if (self.global_error_set.getEntry(name)) |some| return some.*;
20872087
2088 try self.global_error_set.put(self.gpa, try self.gpa.dupe(u8, name), new_val);
2089 return new_val;
2088 const duped = try self.gpa.dupe(u8, name);
2089 errdefer self.gpa.free(duped);
2090
2091 try self.global_error_set.put(self.gpa, duped, new_val);
2092 return self.global_error_set.getEntry(duped).?.*;
20902093}
20912094
20922095/// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites.
src-self-hosted/astgen.zig+28-23
......@@ -247,7 +247,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
247247 .Return => return ret(mod, scope, node.castTag(.Return).?),
248248 .If => return ifExpr(mod, scope, rl, node.castTag(.If).?),
249249 .While => return whileExpr(mod, scope, rl, node.castTag(.While).?),
250 .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)),
250 .Period => return field(mod, scope, rl, node.castTag(.Period).?),
251251 .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)),
252252 .AddressOf => return rlWrap(mod, scope, rl, try addressOf(mod, scope, node.castTag(.AddressOf).?)),
253253 .FloatLiteral => return rlWrap(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)),
......@@ -270,7 +270,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
270270 .ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)),
271271 .MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)),
272272 .AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)),
273 .ErrorSetDecl => return rlWrap(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)),
273 .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?),
274 .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
274275
275276 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
276277 .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
......@@ -290,7 +291,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
290291 .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}),
291292 .Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}),
292293 .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),
293 .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}),
294294 .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
295295 .ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
296296 .Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),
......@@ -722,13 +722,10 @@ fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Si
722722 const src = tree.token_locs[node.rtoken].start;
723723
724724 const operand = try expr(mod, scope, .ref, node.lhs);
725 const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);
726 if (rl == .lvalue or rl == .ref) return unwrapped_ptr;
727
728 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
725 return rlWrapPtr(mod, scope, rl, try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand));
729726}
730727
731fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
728fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
732729 const tree = scope.tree();
733730 const src = tree.token_locs[node.error_token].start;
734731 const decls = node.decls();
......@@ -739,7 +736,17 @@ fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) Inner
739736 fields[i] = try identifierTokenString(mod, scope, tag.name_token);
740737 }
741738
742 return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{});
739 // analyzing the error set results in a decl ref, so we might need to dereference it
740 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}));
741}
742
743fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
744 const tree = scope.tree();
745 const src = tree.token_locs[node.token].start;
746 return addZIRInstConst(mod, scope, src, .{
747 .ty = Type.initTag(.type),
748 .val = Value.initTag(.anyerror_type),
749 });
743750}
744751
745752/// Return whether the identifier names of two tokens are equal. Resolves @"" tokens without allocating.
......@@ -779,16 +786,16 @@ pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.OneToke
779786 return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = ident_name }, .{});
780787}
781788
782fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
783 // TODO introduce lvalues
789fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
784790 const tree = scope.tree();
785791 const src = tree.token_locs[node.op_token].start;
786792
787 const lhs = try expr(mod, scope, .none, node.lhs);
793 const lhs = try expr(mod, scope, .ref, node.lhs);
788794 const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);
789795
790796 const pointer = try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{});
791 return addZIRUnOp(mod, scope, src, .deref, pointer);
797 if (rl == .ref or rl == .lvalue) return pointer;
798 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, pointer));
792799}
793800
794801fn deref(mod: *Module, scope: *Scope, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
......@@ -1274,12 +1281,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
12741281 .local_ptr => {
12751282 const local_ptr = s.cast(Scope.LocalPtr).?;
12761283 if (mem.eql(u8, local_ptr.name, ident_name)) {
1277 if (rl == .lvalue or rl == .ref) {
1278 return local_ptr.ptr;
1279 } else {
1280 const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr);
1281 return rlWrap(mod, scope, rl, result);
1282 }
1284 return rlWrapPtr(mod, scope, rl, local_ptr.ptr);
12831285 }
12841286 s = local_ptr.parent;
12851287 },
......@@ -1289,10 +1291,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
12891291 }
12901292
12911293 if (mod.lookupDeclName(scope, ident_name)) |decl| {
1292 const result = try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
1293 if (rl == .lvalue or rl == .ref)
1294 return result;
1295 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, result));
1294 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}));
12961295 }
12971296
12981297 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{}'", .{ident_name});
......@@ -1886,6 +1885,12 @@ fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, resul
18861885 return rlWrap(mod, scope, rl, void_inst);
18871886}
18881887
1888fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst {
1889 if (rl == .lvalue or rl == .ref) return ptr;
1890
1891 return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, ptr.src, .deref, ptr));
1892}
1893
18891894pub fn addZIRInstSpecial(
18901895 mod: *Module,
18911896 scope: *Scope,
src-self-hosted/value.zig+26-2
......@@ -92,6 +92,7 @@ pub const Value = extern union {
9292 float_128,
9393 enum_literal,
9494 error_set,
95 @"error",
9596
9697 pub const last_no_payload_tag = Tag.bool_false;
9798 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
......@@ -244,9 +245,10 @@ pub const Value = extern union {
244245 };
245246 return Value{ .ptr_otherwise = &new_payload.base };
246247 },
248 .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
247249
248250 // memory is managed by the declaration
249 .error_set => return self,
251 .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
250252 }
251253 }
252254
......@@ -358,6 +360,7 @@ pub const Value = extern union {
358360 }
359361 return out_stream.writeAll("}");
360362 },
363 .@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}),
361364 };
362365 }
363366
......@@ -424,6 +427,7 @@ pub const Value = extern union {
424427 .const_slice_u8_type => Type.initTag(.const_slice_u8),
425428 .enum_literal_type => Type.initTag(.enum_literal),
426429 .anyframe_type => Type.initTag(.@"anyframe"),
430 .error_set => @panic("TODO error set to type"),
427431
428432 .undef,
429433 .zero,
......@@ -449,7 +453,7 @@ pub const Value = extern union {
449453 .float_64,
450454 .float_128,
451455 .enum_literal,
452 .error_set,
456 .@"error",
453457 => unreachable,
454458 };
455459 }
......@@ -517,6 +521,7 @@ pub const Value = extern union {
517521 .empty_array,
518522 .enum_literal,
519523 .error_set,
524 .@"error",
520525 => unreachable,
521526
522527 .undef => unreachable,
......@@ -597,6 +602,7 @@ pub const Value = extern union {
597602 .empty_array,
598603 .enum_literal,
599604 .error_set,
605 .@"error",
600606 => unreachable,
601607
602608 .undef => unreachable,
......@@ -677,6 +683,7 @@ pub const Value = extern union {
677683 .empty_array,
678684 .enum_literal,
679685 .error_set,
686 .@"error",
680687 => unreachable,
681688
682689 .undef => unreachable,
......@@ -784,6 +791,7 @@ pub const Value = extern union {
784791 .empty_array,
785792 .enum_literal,
786793 .error_set,
794 .@"error",
787795 => unreachable,
788796
789797 .zero,
......@@ -868,6 +876,7 @@ pub const Value = extern union {
868876 .empty_array,
869877 .enum_literal,
870878 .error_set,
879 .@"error",
871880 => unreachable,
872881
873882 .zero,
......@@ -1036,6 +1045,7 @@ pub const Value = extern union {
10361045 .unreachable_value,
10371046 .enum_literal,
10381047 .error_set,
1048 .@"error",
10391049 => unreachable,
10401050
10411051 .zero => false,
......@@ -1107,6 +1117,7 @@ pub const Value = extern union {
11071117 .empty_array,
11081118 .enum_literal,
11091119 .error_set,
1120 .@"error",
11101121 => unreachable,
11111122
11121123 .zero,
......@@ -1251,6 +1262,7 @@ pub const Value = extern union {
12511262 .empty_array,
12521263 .enum_literal,
12531264 .error_set,
1265 .@"error",
12541266 => unreachable,
12551267
12561268 .ref_val => self.cast(Payload.RefVal).?.val,
......@@ -1332,6 +1344,7 @@ pub const Value = extern union {
13321344 .unreachable_value,
13331345 .enum_literal,
13341346 .error_set,
1347 .@"error",
13351348 => unreachable,
13361349
13371350 .empty_array => unreachable, // out of bounds array index
......@@ -1430,6 +1443,7 @@ pub const Value = extern union {
14301443 .void_value,
14311444 .enum_literal,
14321445 .error_set,
1446 .@"error",
14331447 => false,
14341448
14351449 .undef => unreachable,
......@@ -1566,6 +1580,16 @@ pub const Value = extern union {
15661580 // TODO revisit this when we have the concept of the error tag type
15671581 fields: std.StringHashMapUnmanaged(u16),
15681582 };
1583
1584 pub const Error = struct {
1585 base: Payload = .{ .tag = .@"error" },
1586
1587 // TODO revisit this when we have the concept of the error tag type
1588 /// `name` is owned by `Module` and will be valid for the entire
1589 /// duration of the compilation.
1590 name: []const u8,
1591 value: u16,
1592 };
15691593 };
15701594
15711595 /// Big enough to fit any non-BigInt value
src-self-hosted/zir_sema.zig+35-4
......@@ -740,8 +740,7 @@ fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In
740740}
741741
742742fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError!*Inst {
743 // The bytes references memory inside the ZIR module, which can get deallocated
744 // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
743 // The declarations arena will store the hashmap.
745744 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
746745 errdefer new_decl_arena.deinit();
747746
......@@ -750,8 +749,8 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In
750749 try payload.fields.ensureCapacity(&new_decl_arena.allocator, inst.positionals.fields.len);
751750
752751 for (inst.positionals.fields) |field_name| {
753 const value = try mod.getErrorValue(field_name);
754 if (payload.fields.fetchPutAssumeCapacity(field_name, value)) |prev| {
752 const entry = try mod.getErrorValue(field_name);
753 if (payload.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| {
755754 return mod.fail(scope, inst.base.src, "duplicate error: '{}'", .{field_name});
756755 }
757756 }
......@@ -909,6 +908,38 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
909908 );
910909 }
911910 },
911 .Type => {
912 _ = try mod.resolveConstValue(scope, object_ptr);
913 const result = try mod.analyzeDeref(scope, fieldptr.base.src, object_ptr, object_ptr.src);
914 const val = result.value().?;
915 const child_type = val.toType();
916 switch (child_type.zigTypeTag()) {
917 .ErrorSet => {
918 // TODO resolve inferred error sets
919 const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|
920 (payload.fields.getEntry(field_name) orelse
921 return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).*
922 else
923 try mod.getErrorValue(field_name);
924
925 const error_payload = try scope.arena().create(Value.Payload.Error);
926 error_payload.* = .{
927 .name = entry.key,
928 .value = entry.value,
929 };
930
931 const ref_payload = try scope.arena().create(Value.Payload.RefVal);
932 ref_payload.* = .{ .val = Value.initPayload(&error_payload.base) };
933
934 // TODO if this is accessing the global error set create a `error{field_name}` type
935 return mod.constInst(scope, fieldptr.base.src, .{
936 .ty = try mod.simplePtrType(scope, fieldptr.base.src, child_type, false, .One),
937 .val = Value.initPayload(&ref_payload.base),
938 });
939 },
940 else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}),
941 }
942 },
912943 else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}),
913944 }
914945}