Commit 1520e084cb
Changed files (4)
src-self-hosted
src-self-hosted/astgen.zig
@@ -247,7 +247,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
.Return => return ret(mod, scope, node.castTag(.Return).?),
.If => return ifExpr(mod, scope, rl, node.castTag(.If).?),
.While => return whileExpr(mod, scope, rl, node.castTag(.While).?),
- .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)),
+ .Period => return field(mod, scope, rl, node.castTag(.Period).?),
.Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)),
.AddressOf => return rlWrap(mod, scope, rl, try addressOf(mod, scope, node.castTag(.AddressOf).?)),
.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
.ErrorUnion => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)),
.MergeErrorSets => return rlWrap(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)),
.AnyFrameType => return rlWrap(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)),
- .ErrorSetDecl => return rlWrap(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)),
+ .ErrorSetDecl => return errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?),
+ .ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
.Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
.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
.Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}),
.Continue => return mod.failNode(scope, node, "TODO implement astgen.expr for .Continue", .{}),
.AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}),
- .ErrorType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorType", .{}),
.FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}),
.ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
.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
const src = tree.token_locs[node.rtoken].start;
const operand = try expr(mod, scope, .ref, node.lhs);
- const unwrapped_ptr = try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand);
- if (rl == .lvalue or rl == .ref) return unwrapped_ptr;
-
- return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
+ return rlWrapPtr(mod, scope, rl, try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand));
}
-fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
+fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
const tree = scope.tree();
const src = tree.token_locs[node.error_token].start;
const decls = node.decls();
@@ -739,7 +736,17 @@ fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) Inner
fields[i] = try identifierTokenString(mod, scope, tag.name_token);
}
- return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{});
+ // analyzing the error set results in a decl ref, so we might need to dereference it
+ return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}));
+}
+
+fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
+ const tree = scope.tree();
+ const src = tree.token_locs[node.token].start;
+ return addZIRInstConst(mod, scope, src, .{
+ .ty = Type.initTag(.type),
+ .val = Value.initTag(.anyerror_type),
+ });
}
/// 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
return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = ident_name }, .{});
}
-fn field(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
- // TODO introduce lvalues
+fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
const tree = scope.tree();
const src = tree.token_locs[node.op_token].start;
- const lhs = try expr(mod, scope, .none, node.lhs);
+ const lhs = try expr(mod, scope, .ref, node.lhs);
const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);
const pointer = try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{});
- return addZIRUnOp(mod, scope, src, .deref, pointer);
+ if (rl == .ref or rl == .lvalue) return pointer;
+ return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, pointer));
}
fn 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
.local_ptr => {
const local_ptr = s.cast(Scope.LocalPtr).?;
if (mem.eql(u8, local_ptr.name, ident_name)) {
- if (rl == .lvalue or rl == .ref) {
- return local_ptr.ptr;
- } else {
- const result = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr);
- return rlWrap(mod, scope, rl, result);
- }
+ return rlWrapPtr(mod, scope, rl, local_ptr.ptr);
}
s = local_ptr.parent;
},
@@ -1289,10 +1291,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
}
if (mod.lookupDeclName(scope, ident_name)) |decl| {
- const result = try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{});
- if (rl == .lvalue or rl == .ref)
- return result;
- return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, result));
+ return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}));
}
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
return rlWrap(mod, scope, rl, void_inst);
}
+fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst {
+ if (rl == .lvalue or rl == .ref) return ptr;
+
+ return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, ptr.src, .deref, ptr));
+}
+
pub fn addZIRInstSpecial(
mod: *Module,
scope: *Scope,
src-self-hosted/Module.zig
@@ -2081,12 +2081,15 @@ fn createNewDecl(
}
/// Get error value for error tag `name`.
-pub fn getErrorValue(self: *Module, name: []const u8) !u16 {
+pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {
const new_val = @intCast(u16, self.global_error_set.items().len);
- if (self.global_error_set.get(name)) |some| return some;
+ if (self.global_error_set.getEntry(name)) |some| return some.*;
- try self.global_error_set.put(self.gpa, try self.gpa.dupe(u8, name), new_val);
- return new_val;
+ const duped = try self.gpa.dupe(u8, name);
+ errdefer self.gpa.free(duped);
+
+ try self.global_error_set.put(self.gpa, duped, new_val);
+ return self.global_error_set.getEntry(duped).?.*;
}
/// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites.
src-self-hosted/value.zig
@@ -92,6 +92,7 @@ pub const Value = extern union {
float_128,
enum_literal,
error_set,
+ @"error",
pub const last_no_payload_tag = Tag.bool_false;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
@@ -244,9 +245,10 @@ pub const Value = extern union {
};
return Value{ .ptr_otherwise = &new_payload.base };
},
+ .@"error" => return self.copyPayloadShallow(allocator, Payload.Error),
// memory is managed by the declaration
- .error_set => return self,
+ .error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
}
}
@@ -358,6 +360,7 @@ pub const Value = extern union {
}
return out_stream.writeAll("}");
},
+ .@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}),
};
}
@@ -424,6 +427,7 @@ pub const Value = extern union {
.const_slice_u8_type => Type.initTag(.const_slice_u8),
.enum_literal_type => Type.initTag(.enum_literal),
.anyframe_type => Type.initTag(.@"anyframe"),
+ .error_set => @panic("TODO error set to type"),
.undef,
.zero,
@@ -449,7 +453,7 @@ pub const Value = extern union {
.float_64,
.float_128,
.enum_literal,
- .error_set,
+ .@"error",
=> unreachable,
};
}
@@ -517,6 +521,7 @@ pub const Value = extern union {
.empty_array,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.undef => unreachable,
@@ -597,6 +602,7 @@ pub const Value = extern union {
.empty_array,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.undef => unreachable,
@@ -677,6 +683,7 @@ pub const Value = extern union {
.empty_array,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.undef => unreachable,
@@ -784,6 +791,7 @@ pub const Value = extern union {
.empty_array,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.zero,
@@ -868,6 +876,7 @@ pub const Value = extern union {
.empty_array,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.zero,
@@ -1036,6 +1045,7 @@ pub const Value = extern union {
.unreachable_value,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.zero => false,
@@ -1107,6 +1117,7 @@ pub const Value = extern union {
.empty_array,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.zero,
@@ -1251,6 +1262,7 @@ pub const Value = extern union {
.empty_array,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.ref_val => self.cast(Payload.RefVal).?.val,
@@ -1332,6 +1344,7 @@ pub const Value = extern union {
.unreachable_value,
.enum_literal,
.error_set,
+ .@"error",
=> unreachable,
.empty_array => unreachable, // out of bounds array index
@@ -1430,6 +1443,7 @@ pub const Value = extern union {
.void_value,
.enum_literal,
.error_set,
+ .@"error",
=> false,
.undef => unreachable,
@@ -1566,6 +1580,16 @@ pub const Value = extern union {
// TODO revisit this when we have the concept of the error tag type
fields: std.StringHashMapUnmanaged(u16),
};
+
+ pub const Error = struct {
+ base: Payload = .{ .tag = .@"error" },
+
+ // TODO revisit this when we have the concept of the error tag type
+ /// `name` is owned by `Module` and will be valid for the entire
+ /// duration of the compilation.
+ name: []const u8,
+ value: u16,
+ };
};
/// Big enough to fit any non-BigInt value
src-self-hosted/zir_sema.zig
@@ -740,8 +740,7 @@ fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In
}
fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError!*Inst {
- // The bytes references memory inside the ZIR module, which can get deallocated
- // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
+ // The declarations arena will store the hashmap.
var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
errdefer new_decl_arena.deinit();
@@ -750,8 +749,8 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In
try payload.fields.ensureCapacity(&new_decl_arena.allocator, inst.positionals.fields.len);
for (inst.positionals.fields) |field_name| {
- const value = try mod.getErrorValue(field_name);
- if (payload.fields.fetchPutAssumeCapacity(field_name, value)) |prev| {
+ const entry = try mod.getErrorValue(field_name);
+ if (payload.fields.fetchPutAssumeCapacity(entry.key, entry.value)) |prev| {
return mod.fail(scope, inst.base.src, "duplicate error: '{}'", .{field_name});
}
}
@@ -909,6 +908,38 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
);
}
},
+ .Type => {
+ _ = try mod.resolveConstValue(scope, object_ptr);
+ const result = try mod.analyzeDeref(scope, fieldptr.base.src, object_ptr, object_ptr.src);
+ const val = result.value().?;
+ const child_type = val.toType();
+ switch (child_type.zigTypeTag()) {
+ .ErrorSet => {
+ // TODO resolve inferred error sets
+ const entry = if (val.cast(Value.Payload.ErrorSet)) |payload|
+ (payload.fields.getEntry(field_name) orelse
+ return mod.fail(scope, fieldptr.base.src, "no error named '{}' in '{}'", .{ field_name, child_type })).*
+ else
+ try mod.getErrorValue(field_name);
+
+ const error_payload = try scope.arena().create(Value.Payload.Error);
+ error_payload.* = .{
+ .name = entry.key,
+ .value = entry.value,
+ };
+
+ const ref_payload = try scope.arena().create(Value.Payload.RefVal);
+ ref_payload.* = .{ .val = Value.initPayload(&error_payload.base) };
+
+ // TODO if this is accessing the global error set create a `error{field_name}` type
+ return mod.constInst(scope, fieldptr.base.src, .{
+ .ty = try mod.simplePtrType(scope, fieldptr.base.src, child_type, false, .One),
+ .val = Value.initPayload(&ref_payload.base),
+ });
+ },
+ else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{child_type}),
+ }
+ },
else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}),
}
}