mirror of
https://github.com/ziglang/zig.git
synced 2026-01-12 02:15:12 +00:00
commit
b30c538076
@ -80,6 +80,9 @@ deletion_set: std.ArrayListUnmanaged(*Decl) = .{},
|
||||
root_name: []u8,
|
||||
keep_source_files_loaded: bool,
|
||||
|
||||
/// Error tags and their values, tag names are duped with mod.gpa.
|
||||
global_error_set: std.StringHashMapUnmanaged(u16) = .{},
|
||||
|
||||
pub const InnerError = error{ OutOfMemory, AnalysisFail };
|
||||
|
||||
const WorkItem = union(enum) {
|
||||
@ -928,6 +931,11 @@ pub fn deinit(self: *Module) void {
|
||||
|
||||
self.symbol_exports.deinit(gpa);
|
||||
self.root_scope.destroy(gpa);
|
||||
|
||||
for (self.global_error_set.items()) |entry| {
|
||||
gpa.free(entry.key);
|
||||
}
|
||||
self.global_error_set.deinit(gpa);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
@ -2072,6 +2080,18 @@ fn createNewDecl(
|
||||
return new_decl;
|
||||
}
|
||||
|
||||
/// Get error value for error tag `name`.
|
||||
pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {
|
||||
const gop = try self.global_error_set.getOrPut(self.gpa, name);
|
||||
if (gop.found_existing)
|
||||
return gop.entry.*;
|
||||
errdefer self.global_error_set.removeAssertDiscard(name);
|
||||
|
||||
gop.entry.key = try self.gpa.dupe(u8, name);
|
||||
gop.entry.value = @intCast(u16, self.global_error_set.items().len - 1);
|
||||
return gop.entry.*;
|
||||
}
|
||||
|
||||
/// TODO split this into `requireRuntimeBlock` and `requireFunctionBlock` and audit callsites.
|
||||
pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
|
||||
return scope.cast(Scope.Block) orelse
|
||||
@ -3309,6 +3329,28 @@ pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_
|
||||
return Type.initPayload(&payload.base);
|
||||
}
|
||||
|
||||
pub fn errorUnionType(self: *Module, scope: *Scope, error_set: Type, payload: Type) Allocator.Error!Type {
|
||||
assert(error_set.zigTypeTag() == .ErrorSet);
|
||||
if (error_set.eql(Type.initTag(.anyerror)) and payload.eql(Type.initTag(.void))) {
|
||||
return Type.initTag(.anyerror_void_error_union);
|
||||
}
|
||||
|
||||
const result = try scope.arena().create(Type.Payload.ErrorUnion);
|
||||
result.* = .{
|
||||
.error_set = error_set,
|
||||
.payload = payload,
|
||||
};
|
||||
return Type.initPayload(&result.base);
|
||||
}
|
||||
|
||||
pub fn anyframeType(self: *Module, scope: *Scope, return_type: Type) Allocator.Error!Type {
|
||||
const result = try scope.arena().create(Type.Payload.AnyFrame);
|
||||
result.* = .{
|
||||
.return_type = return_type,
|
||||
};
|
||||
return Type.initPayload(&result.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");
|
||||
|
||||
@ -232,6 +232,11 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?),
|
||||
.BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?),
|
||||
|
||||
.BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)),
|
||||
.BitNot => return rlWrap(mod, scope, rl, try bitNot(mod, scope, node.castTag(.BitNot).?)),
|
||||
.Negation => return rlWrap(mod, scope, rl, try negation(mod, scope, node.castTag(.Negation).?, .sub)),
|
||||
.NegationWrap => return rlWrap(mod, scope, rl, try negation(mod, scope, node.castTag(.NegationWrap).?, .subwrap)),
|
||||
|
||||
.Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?),
|
||||
.Asm => return rlWrap(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)),
|
||||
.StringLiteral => return rlWrap(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)),
|
||||
@ -242,9 +247,8 @@ 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).?)),
|
||||
.BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)),
|
||||
.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).?)),
|
||||
.UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)),
|
||||
@ -263,17 +267,17 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.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).?)),
|
||||
.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 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", .{}),
|
||||
.ErrorUnion => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorUnion", .{}),
|
||||
.MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}),
|
||||
.Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
|
||||
.OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),
|
||||
.Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
|
||||
.BitNot => return mod.failNode(scope, node, "TODO implement astgen.expr for .BitNot", .{}),
|
||||
.Negation => return mod.failNode(scope, node, "TODO implement astgen.expr for .Negation", .{}),
|
||||
.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", .{}),
|
||||
.Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
|
||||
@ -287,10 +291,7 @@ 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", .{}),
|
||||
.AnyFrameType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyFrameType", .{}),
|
||||
.ErrorSetDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ErrorSetDecl", .{}),
|
||||
.ContainerDecl => return mod.failNode(scope, node, "TODO implement astgen.expr for .ContainerDecl", .{}),
|
||||
.Comptime => return mod.failNode(scope, node, "TODO implement astgen.expr for .Comptime", .{}),
|
||||
.Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}),
|
||||
@ -458,7 +459,9 @@ fn varDecl(
|
||||
const tree = scope.tree();
|
||||
const name_src = tree.token_locs[node.name_token].start;
|
||||
const ident_name = try identifierTokenString(mod, scope, node.name_token);
|
||||
const init_node = node.getTrailer("init_node").?;
|
||||
const init_node = node.getTrailer("init_node") orelse
|
||||
return mod.fail(scope, name_src, "variables must be initialized", .{});
|
||||
|
||||
switch (tree.token_ids[node.mut_token]) {
|
||||
.Keyword_const => {
|
||||
// Depending on the type of AST the initialization expression is, we may need an lvalue
|
||||
@ -554,6 +557,26 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr
|
||||
return addZIRUnOp(mod, scope, src, .boolnot, operand);
|
||||
}
|
||||
|
||||
fn bitNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.op_token].start;
|
||||
const operand = try expr(mod, scope, .none, node.rhs);
|
||||
return addZIRUnOp(mod, scope, src, .bitnot, operand);
|
||||
}
|
||||
|
||||
fn negation(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.op_token].start;
|
||||
|
||||
const lhs = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.comptime_int),
|
||||
.val = Value.initTag(.zero),
|
||||
});
|
||||
const rhs = try expr(mod, scope, .none, node.rhs);
|
||||
|
||||
return addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs);
|
||||
}
|
||||
|
||||
fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
|
||||
return expr(mod, scope, .ref, node.rhs);
|
||||
}
|
||||
@ -561,11 +584,7 @@ fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerE
|
||||
fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) 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),
|
||||
});
|
||||
const operand = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
const operand = try typeExpr(mod, scope, node.rhs);
|
||||
return addZIRUnOp(mod, scope, src, .optional_type, operand);
|
||||
}
|
||||
|
||||
@ -590,18 +609,13 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir
|
||||
}
|
||||
|
||||
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 }, rhs);
|
||||
const child_type = try typeExpr(mod, scope, rhs);
|
||||
const mutable = ptr_info.const_token == null;
|
||||
// TODO stage1 type inference bug
|
||||
const T = zir.Inst.Tag;
|
||||
@ -629,7 +643,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,
|
||||
kw_args.sentinel = try expr(mod, scope, .none, some);
|
||||
}
|
||||
|
||||
const child_type = try expr(mod, scope, .{ .ty = meta_type }, rhs);
|
||||
const child_type = try typeExpr(mod, scope, rhs);
|
||||
if (kw_args.sentinel) |some| {
|
||||
kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some);
|
||||
}
|
||||
@ -640,10 +654,6 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo,
|
||||
fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*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),
|
||||
});
|
||||
const usize_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.usize_type),
|
||||
@ -651,18 +661,14 @@ fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst
|
||||
|
||||
// TODO check for [_]T
|
||||
const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
|
||||
const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
const elem_type = try typeExpr(mod, scope, node.rhs);
|
||||
|
||||
return addZIRBinOp(mod, scope, src, .array_type, len, child_type);
|
||||
return addZIRBinOp(mod, scope, src, .array_type, len, elem_type);
|
||||
}
|
||||
|
||||
fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*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),
|
||||
});
|
||||
const usize_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.usize_type),
|
||||
@ -671,7 +677,7 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti
|
||||
// TODO check for [_]T
|
||||
const len = try expr(mod, scope, .{ .ty = usize_type }, node.len_expr);
|
||||
const sentinel_uncasted = try expr(mod, scope, .none, node.sentinel);
|
||||
const elem_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
const elem_type = try typeExpr(mod, scope, node.rhs);
|
||||
const sentinel = try addZIRBinOp(mod, scope, src, .as, elem_type, sentinel_uncasted);
|
||||
|
||||
return addZIRInst(mod, scope, src, zir.Inst.ArrayTypeSentinel, .{
|
||||
@ -681,6 +687,28 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti
|
||||
}, .{});
|
||||
}
|
||||
|
||||
fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.anyframe_token].start;
|
||||
if (node.result) |some| {
|
||||
const return_type = try typeExpr(mod, scope, some.return_type);
|
||||
return addZIRUnOp(mod, scope, src, .anyframe_type, return_type);
|
||||
} else {
|
||||
return addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.anyframe_type),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_inst_tag: zir.Inst.Tag) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.op_token].start;
|
||||
const error_set = try typeExpr(mod, scope, node.lhs);
|
||||
const payload = try typeExpr(mod, scope, node.rhs);
|
||||
return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload);
|
||||
}
|
||||
|
||||
fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.EnumLiteral) !*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.name].start;
|
||||
@ -694,10 +722,31 @@ 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 rlWrapPtr(mod, scope, rl, try addZIRUnOp(mod, scope, src, .unwrap_optional_safe, operand));
|
||||
}
|
||||
|
||||
return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, src, .deref, unwrapped_ptr));
|
||||
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();
|
||||
const fields = try scope.arena().alloc([]const u8, decls.len);
|
||||
|
||||
for (decls) |decl, i| {
|
||||
const tag = decl.castTag(.ErrorTag).?;
|
||||
fields[i] = try identifierTokenString(mod, scope, tag.name_token);
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -737,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 {
|
||||
@ -1232,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;
|
||||
},
|
||||
@ -1247,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});
|
||||
@ -1466,12 +1507,8 @@ fn simpleCast(
|
||||
try ensureBuiltinParamCount(mod, scope, call, 2);
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[call.builtin_token].start;
|
||||
const type_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
const params = call.params();
|
||||
const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]);
|
||||
const dest_type = try typeExpr(mod, scope, params[0]);
|
||||
const rhs = try expr(mod, scope, .none, params[1]);
|
||||
const result = try addZIRBinOp(mod, scope, src, inst_tag, dest_type, rhs);
|
||||
return rlWrap(mod, scope, rl, result);
|
||||
@ -1533,12 +1570,8 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa
|
||||
try ensureBuiltinParamCount(mod, scope, call, 2);
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[call.builtin_token].start;
|
||||
const type_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
const params = call.params();
|
||||
const dest_type = try expr(mod, scope, .{ .ty = type_type }, params[0]);
|
||||
const dest_type = try typeExpr(mod, scope, params[0]);
|
||||
switch (rl) {
|
||||
.none => {
|
||||
const operand = try expr(mod, scope, .none, params[1]);
|
||||
@ -1852,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,
|
||||
|
||||
@ -3,6 +3,7 @@ const Value = @import("value.zig").Value;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Target = std.Target;
|
||||
const Module = @import("Module.zig");
|
||||
|
||||
/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.
|
||||
/// It's important for this type to be small.
|
||||
@ -52,7 +53,7 @@ pub const Type = extern union {
|
||||
.bool => return .Bool,
|
||||
.void => return .Void,
|
||||
.type => return .Type,
|
||||
.anyerror => return .ErrorSet,
|
||||
.error_set, .error_set_single, .anyerror => return .ErrorSet,
|
||||
.comptime_int => return .ComptimeInt,
|
||||
.comptime_float => return .ComptimeFloat,
|
||||
.noreturn => return .NoReturn,
|
||||
@ -84,6 +85,10 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
=> return .Optional,
|
||||
.enum_literal => return .EnumLiteral,
|
||||
|
||||
.anyerror_void_error_union, .error_union => return .ErrorUnion,
|
||||
|
||||
.anyframe_T, .@"anyframe" => return .AnyFrame,
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,6 +156,9 @@ pub const Type = extern union {
|
||||
.ComptimeInt => return true,
|
||||
.Undefined => return true,
|
||||
.Null => return true,
|
||||
.AnyFrame => {
|
||||
return a.elemType().eql(b.elemType());
|
||||
},
|
||||
.Pointer => {
|
||||
// Hot path for common case:
|
||||
if (a.castPointer()) |a_payload| {
|
||||
@ -225,7 +233,6 @@ pub const Type = extern union {
|
||||
.BoundFn,
|
||||
.Opaque,
|
||||
.Frame,
|
||||
.AnyFrame,
|
||||
.Vector,
|
||||
=> std.debug.panic("TODO implement Type equality comparison of {} and {}", .{ a, b }),
|
||||
}
|
||||
@ -343,6 +350,8 @@ pub const Type = extern union {
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.const_slice_u8,
|
||||
.enum_literal,
|
||||
.anyerror_void_error_union,
|
||||
.@"anyframe",
|
||||
=> unreachable,
|
||||
|
||||
.array_u8_sentinel_0 => return self.copyPayloadShallow(allocator, Payload.Array_u8_Sentinel0),
|
||||
@ -397,6 +406,7 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
=> return self.copyPayloadSingleField(allocator, Payload.PointerSimple, "pointee_type"),
|
||||
.anyframe_T => return self.copyPayloadSingleField(allocator, Payload.AnyFrame, "return_type"),
|
||||
|
||||
.pointer => {
|
||||
const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
|
||||
@ -416,6 +426,19 @@ pub const Type = extern union {
|
||||
};
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.error_union => {
|
||||
const payload = @fieldParentPtr(Payload.ErrorUnion, "base", self.ptr_otherwise);
|
||||
const new_payload = try allocator.create(Payload.ErrorUnion);
|
||||
new_payload.* = .{
|
||||
.base = payload.base,
|
||||
|
||||
.error_set = try payload.error_set.copy(allocator),
|
||||
.payload = try payload.payload.copy(allocator),
|
||||
};
|
||||
return Type{ .ptr_otherwise = &new_payload.base };
|
||||
},
|
||||
.error_set => return self.copyPayloadShallow(allocator, Payload.ErrorSet),
|
||||
.error_set_single => return self.copyPayloadShallow(allocator, Payload.ErrorSetSingle),
|
||||
}
|
||||
}
|
||||
|
||||
@ -482,6 +505,8 @@ pub const Type = extern union {
|
||||
.@"null" => return out_stream.writeAll("@TypeOf(null)"),
|
||||
.@"undefined" => return out_stream.writeAll("@TypeOf(undefined)"),
|
||||
|
||||
.@"anyframe" => return out_stream.writeAll("anyframe"),
|
||||
.anyerror_void_error_union => return out_stream.writeAll("anyerror!void"),
|
||||
.const_slice_u8 => return out_stream.writeAll("[]const u8"),
|
||||
.fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
|
||||
.fn_void_no_args => return out_stream.writeAll("fn() void"),
|
||||
@ -500,6 +525,12 @@ pub const Type = extern union {
|
||||
continue;
|
||||
},
|
||||
|
||||
.anyframe_T => {
|
||||
const payload = @fieldParentPtr(Payload.AnyFrame, "base", ty.ptr_otherwise);
|
||||
try out_stream.print("anyframe->", .{});
|
||||
ty = payload.return_type;
|
||||
continue;
|
||||
},
|
||||
.array_u8 => {
|
||||
const payload = @fieldParentPtr(Payload.Array_u8, "base", ty.ptr_otherwise);
|
||||
return out_stream.print("[{}]u8", .{payload.len});
|
||||
@ -622,6 +653,21 @@ pub const Type = extern union {
|
||||
ty = payload.pointee_type;
|
||||
continue;
|
||||
},
|
||||
.error_union => {
|
||||
const payload = @fieldParentPtr(Payload.ErrorUnion, "base", ty.ptr_otherwise);
|
||||
try payload.error_set.format("", .{}, out_stream);
|
||||
try out_stream.writeAll("!");
|
||||
ty = payload.payload;
|
||||
continue;
|
||||
},
|
||||
.error_set => {
|
||||
const payload = @fieldParentPtr(Payload.ErrorSet, "base", ty.ptr_otherwise);
|
||||
return out_stream.writeAll(std.mem.spanZ(payload.decl.name));
|
||||
},
|
||||
.error_set_single => {
|
||||
const payload = @fieldParentPtr(Payload.ErrorSetSingle, "base", ty.ptr_otherwise);
|
||||
return out_stream.print("error{{{}}}", .{payload.name});
|
||||
},
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
@ -715,6 +761,11 @@ pub const Type = extern union {
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> true,
|
||||
// TODO lazy types
|
||||
.array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
|
||||
@ -723,6 +774,11 @@ pub const Type = extern union {
|
||||
.int_signed => self.cast(Payload.IntSigned).?.bits == 0,
|
||||
.int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0,
|
||||
|
||||
.error_union => {
|
||||
const payload = self.cast(Payload.ErrorUnion).?;
|
||||
return payload.error_set.hasCodeGenBits() or payload.payload.hasCodeGenBits();
|
||||
},
|
||||
|
||||
.c_void,
|
||||
.void,
|
||||
.type,
|
||||
@ -779,6 +835,8 @@ pub const Type = extern union {
|
||||
.mut_slice,
|
||||
.optional_single_const_pointer,
|
||||
.optional_single_mut_pointer,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
=> return @divExact(target.cpu.arch.ptrBitWidth(), 8),
|
||||
|
||||
.pointer => {
|
||||
@ -803,7 +861,11 @@ pub const Type = extern union {
|
||||
.f128 => return 16,
|
||||
.c_longdouble => return 16,
|
||||
|
||||
.anyerror => return 2, // TODO revisit this when we have the concept of the error tag type
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.anyerror_void_error_union,
|
||||
.anyerror,
|
||||
=> return 2, // TODO revisit this when we have the concept of the error tag type
|
||||
|
||||
.array, .array_sentinel => return self.elemType().abiAlignment(target),
|
||||
|
||||
@ -829,6 +891,16 @@ pub const Type = extern union {
|
||||
return child_type.abiAlignment(target);
|
||||
},
|
||||
|
||||
.error_union => {
|
||||
const payload = self.cast(Payload.ErrorUnion).?;
|
||||
if (!payload.error_set.hasCodeGenBits()) {
|
||||
return payload.payload.abiAlignment(target);
|
||||
} else if (!payload.payload.hasCodeGenBits()) {
|
||||
return payload.error_set.abiAlignment(target);
|
||||
}
|
||||
@panic("TODO abiAlignment error union");
|
||||
},
|
||||
|
||||
.c_void,
|
||||
.void,
|
||||
.type,
|
||||
@ -882,12 +954,15 @@ pub const Type = extern union {
|
||||
.i32, .u32 => return 4,
|
||||
.i64, .u64 => return 8,
|
||||
|
||||
.isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
|
||||
.@"anyframe", .anyframe_T, .isize, .usize => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
|
||||
|
||||
.const_slice,
|
||||
.mut_slice,
|
||||
.const_slice_u8,
|
||||
=> return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2,
|
||||
=> {
|
||||
if (self.elemType().hasCodeGenBits()) return @divExact(target.cpu.arch.ptrBitWidth(), 8) * 2;
|
||||
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,
|
||||
@ -923,7 +998,11 @@ pub const Type = extern union {
|
||||
.f128 => return 16,
|
||||
.c_longdouble => return 16,
|
||||
|
||||
.anyerror => return 2, // TODO revisit this when we have the concept of the error tag type
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
.anyerror_void_error_union,
|
||||
.anyerror,
|
||||
=> return 2, // TODO revisit this when we have the concept of the error tag type
|
||||
|
||||
.int_signed, .int_unsigned => {
|
||||
const bits: u16 = if (self.cast(Payload.IntSigned)) |pl|
|
||||
@ -950,6 +1029,18 @@ pub const Type = extern union {
|
||||
// to the child type's ABI alignment.
|
||||
return child_type.abiAlignment(target) + child_type.abiSize(target);
|
||||
},
|
||||
|
||||
.error_union => {
|
||||
const payload = self.cast(Payload.ErrorUnion).?;
|
||||
if (!payload.error_set.hasCodeGenBits() and !payload.payload.hasCodeGenBits()) {
|
||||
return 0;
|
||||
} else if (!payload.error_set.hasCodeGenBits()) {
|
||||
return payload.payload.abiSize(target);
|
||||
} else if (!payload.payload.hasCodeGenBits()) {
|
||||
return payload.error_set.abiSize(target);
|
||||
}
|
||||
@panic("TODO abiSize error union");
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -1010,6 +1101,12 @@ pub const Type = extern union {
|
||||
.c_mut_pointer,
|
||||
.const_slice,
|
||||
.mut_slice,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer,
|
||||
@ -1078,6 +1175,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
|
||||
.const_slice,
|
||||
@ -1143,6 +1246,12 @@ pub const Type = extern union {
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.mut_slice,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer,
|
||||
@ -1217,6 +1326,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
|
||||
.pointer => {
|
||||
@ -1328,6 +1443,12 @@ pub const Type = extern union {
|
||||
.optional_single_const_pointer,
|
||||
.optional_single_mut_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
|
||||
.array => self.cast(Payload.Array).?.elem_type,
|
||||
@ -1449,6 +1570,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
|
||||
.array => self.cast(Payload.Array).?.len,
|
||||
@ -1516,6 +1643,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
|
||||
.array, .array_u8 => return null,
|
||||
@ -1581,6 +1714,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
|
||||
.int_signed,
|
||||
@ -1649,6 +1788,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
|
||||
.int_unsigned,
|
||||
@ -1707,6 +1852,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
|
||||
.int_unsigned => .{ .signed = false, .bits = self.cast(Payload.IntUnsigned).?.bits },
|
||||
@ -1783,6 +1934,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
|
||||
.usize,
|
||||
@ -1888,6 +2045,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -1959,6 +2122,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
@ -2029,6 +2198,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
}
|
||||
}
|
||||
@ -2099,6 +2274,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2166,6 +2347,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2233,6 +2420,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -2300,6 +2493,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> false,
|
||||
};
|
||||
}
|
||||
@ -2351,6 +2550,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.anyerror_void_error_union,
|
||||
.anyframe_T,
|
||||
.@"anyframe",
|
||||
.error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> return null,
|
||||
|
||||
.void => return Value.initTag(.void_value),
|
||||
@ -2454,6 +2659,12 @@ pub const Type = extern union {
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
.enum_literal,
|
||||
.error_union,
|
||||
.@"anyframe",
|
||||
.anyframe_T,
|
||||
.anyerror_void_error_union,
|
||||
.error_set,
|
||||
.error_set_single,
|
||||
=> return false,
|
||||
|
||||
.c_const_pointer,
|
||||
@ -2511,6 +2722,8 @@ pub const Type = extern union {
|
||||
fn_naked_noreturn_no_args,
|
||||
fn_ccc_void_no_args,
|
||||
single_const_pointer_to_comptime_int,
|
||||
anyerror_void_error_union,
|
||||
@"anyframe",
|
||||
const_slice_u8, // See last_no_payload_tag below.
|
||||
// After this, the tag requires a payload.
|
||||
|
||||
@ -2533,6 +2746,10 @@ pub const Type = extern union {
|
||||
optional,
|
||||
optional_single_mut_pointer,
|
||||
optional_single_const_pointer,
|
||||
error_union,
|
||||
anyframe_T,
|
||||
error_set,
|
||||
error_set_single,
|
||||
|
||||
pub const last_no_payload_tag = Tag.const_slice_u8;
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
@ -2614,6 +2831,32 @@ pub const Type = extern union {
|
||||
@"volatile": bool,
|
||||
size: std.builtin.TypeInfo.Pointer.Size,
|
||||
};
|
||||
|
||||
pub const ErrorUnion = struct {
|
||||
base: Payload = .{ .tag = .error_union },
|
||||
|
||||
error_set: Type,
|
||||
payload: Type,
|
||||
};
|
||||
|
||||
pub const AnyFrame = struct {
|
||||
base: Payload = .{ .tag = .anyframe_T },
|
||||
|
||||
return_type: Type,
|
||||
};
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
base: Payload = .{ .tag = .error_set },
|
||||
|
||||
decl: *Module.Decl,
|
||||
};
|
||||
|
||||
pub const ErrorSetSingle = struct {
|
||||
base: Payload = .{ .tag = .error_set_single },
|
||||
|
||||
/// memory is owned by `Module`
|
||||
name: []const u8,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@ -61,6 +61,7 @@ pub const Value = extern union {
|
||||
single_const_pointer_to_comptime_int_type,
|
||||
const_slice_u8_type,
|
||||
enum_literal_type,
|
||||
anyframe_type,
|
||||
|
||||
undef,
|
||||
zero,
|
||||
@ -90,6 +91,8 @@ pub const Value = extern union {
|
||||
float_64,
|
||||
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;
|
||||
@ -168,6 +171,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.undef,
|
||||
.zero,
|
||||
.void_value,
|
||||
@ -241,6 +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.copyPayloadShallow(allocator, Payload.ErrorSet),
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,6 +308,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
|
||||
.const_slice_u8_type => return out_stream.writeAll("[]const u8"),
|
||||
.enum_literal_type => return out_stream.writeAll("@TypeOf(.EnumLiteral)"),
|
||||
.anyframe_type => return out_stream.writeAll("anyframe"),
|
||||
|
||||
.null_value => return out_stream.writeAll("null"),
|
||||
.undef => return out_stream.writeAll("undefined"),
|
||||
@ -343,6 +352,15 @@ pub const Value = extern union {
|
||||
.float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
|
||||
.float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
|
||||
.float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
|
||||
.error_set => {
|
||||
const error_set = val.cast(Payload.ErrorSet).?;
|
||||
try out_stream.writeAll("error{");
|
||||
for (error_set.fields.items()) |entry| {
|
||||
try out_stream.print("{},", .{entry.value});
|
||||
}
|
||||
return out_stream.writeAll("}");
|
||||
},
|
||||
.@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}),
|
||||
};
|
||||
}
|
||||
|
||||
@ -363,11 +381,9 @@ pub const Value = extern union {
|
||||
}
|
||||
|
||||
/// Asserts that the value is representable as a type.
|
||||
pub fn toType(self: Value) Type {
|
||||
pub fn toType(self: Value, allocator: *Allocator) !Type {
|
||||
return switch (self.tag()) {
|
||||
.ty => self.cast(Payload.Ty).?.ty,
|
||||
.int_type => @panic("TODO int type to type"),
|
||||
|
||||
.u8_type => Type.initTag(.u8),
|
||||
.i8_type => Type.initTag(.i8),
|
||||
.u16_type => Type.initTag(.u16),
|
||||
@ -408,6 +424,26 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
.const_slice_u8_type => Type.initTag(.const_slice_u8),
|
||||
.enum_literal_type => Type.initTag(.enum_literal),
|
||||
.anyframe_type => Type.initTag(.@"anyframe"),
|
||||
|
||||
.int_type => {
|
||||
const payload = self.cast(Payload.IntType).?;
|
||||
if (payload.signed) {
|
||||
const new = try allocator.create(Type.Payload.IntSigned);
|
||||
new.* = .{ .bits = payload.bits };
|
||||
return Type.initPayload(&new.base);
|
||||
} else {
|
||||
const new = try allocator.create(Type.Payload.IntUnsigned);
|
||||
new.* = .{ .bits = payload.bits };
|
||||
return Type.initPayload(&new.base);
|
||||
}
|
||||
},
|
||||
.error_set => {
|
||||
const payload = self.cast(Payload.ErrorSet).?;
|
||||
const new = try allocator.create(Type.Payload.ErrorSet);
|
||||
new.* = .{ .decl = payload.decl };
|
||||
return Type.initPayload(&new.base);
|
||||
},
|
||||
|
||||
.undef,
|
||||
.zero,
|
||||
@ -433,6 +469,7 @@ pub const Value = extern union {
|
||||
.float_64,
|
||||
.float_128,
|
||||
.enum_literal,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
};
|
||||
}
|
||||
@ -482,6 +519,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.variable,
|
||||
@ -498,6 +536,8 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -560,6 +600,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.variable,
|
||||
@ -576,6 +617,8 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -638,6 +681,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.variable,
|
||||
@ -654,6 +698,8 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -742,6 +788,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.variable,
|
||||
@ -759,6 +806,8 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -825,6 +874,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.variable,
|
||||
@ -841,6 +891,8 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -988,6 +1040,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
.null_value,
|
||||
@ -1007,6 +1060,8 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.zero => false,
|
||||
@ -1063,6 +1118,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.null_value,
|
||||
.function,
|
||||
.variable,
|
||||
@ -1076,6 +1132,8 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.zero,
|
||||
@ -1197,6 +1255,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.zero,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
@ -1218,6 +1277,8 @@ pub const Value = extern union {
|
||||
.unreachable_value,
|
||||
.empty_array,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.ref_val => self.cast(Payload.RefVal).?.val,
|
||||
@ -1276,6 +1337,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.zero,
|
||||
.bool_true,
|
||||
.bool_false,
|
||||
@ -1297,6 +1359,8 @@ pub const Value = extern union {
|
||||
.void_value,
|
||||
.unreachable_value,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> unreachable,
|
||||
|
||||
.empty_array => unreachable, // out of bounds array index
|
||||
@ -1372,6 +1436,7 @@ pub const Value = extern union {
|
||||
.single_const_pointer_to_comptime_int_type,
|
||||
.const_slice_u8_type,
|
||||
.enum_literal_type,
|
||||
.anyframe_type,
|
||||
.zero,
|
||||
.empty_array,
|
||||
.bool_true,
|
||||
@ -1393,6 +1458,8 @@ pub const Value = extern union {
|
||||
.float_128,
|
||||
.void_value,
|
||||
.enum_literal,
|
||||
.error_set,
|
||||
.@"error",
|
||||
=> false,
|
||||
|
||||
.undef => unreachable,
|
||||
@ -1522,6 +1589,24 @@ pub const Value = extern union {
|
||||
base: Payload = .{ .tag = .float_128 },
|
||||
val: f128,
|
||||
};
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
base: Payload = .{ .tag = .error_set },
|
||||
|
||||
// TODO revisit this when we have the concept of the error tag type
|
||||
fields: std.StringHashMapUnmanaged(u16),
|
||||
decl: *Module.Decl,
|
||||
};
|
||||
|
||||
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
|
||||
|
||||
@ -43,6 +43,8 @@ pub const Inst = struct {
|
||||
alloc,
|
||||
/// Same as `alloc` except the type is inferred.
|
||||
alloc_inferred,
|
||||
/// Create an `anyframe->T`.
|
||||
anyframe_type,
|
||||
/// Array concatenation. `a ++ b`
|
||||
array_cat,
|
||||
/// Array multiplication `a ** b`
|
||||
@ -70,6 +72,8 @@ pub const Inst = struct {
|
||||
/// A typed result location pointer is bitcasted to a new result location pointer.
|
||||
/// The new result location pointer has an inferred type.
|
||||
bitcast_result_ptr,
|
||||
/// Bitwise NOT. `~`
|
||||
bitnot,
|
||||
/// Bitwise OR. `|`
|
||||
bitor,
|
||||
/// A labeled block of code, which can return a value.
|
||||
@ -133,6 +137,10 @@ pub const Inst = struct {
|
||||
ensure_result_used,
|
||||
/// Emits a compile error if an error is ignored.
|
||||
ensure_result_non_error,
|
||||
/// Create a `E!T` type.
|
||||
error_union_type,
|
||||
/// Create an error set.
|
||||
error_set,
|
||||
/// Export the provided Decl as the provided name in the compilation's output object file.
|
||||
@"export",
|
||||
/// Given a pointer to a struct or object that contains virtual fields, returns a pointer
|
||||
@ -160,6 +168,8 @@ pub const Inst = struct {
|
||||
/// A labeled block of code that loops forever. At the end of the body it is implied
|
||||
/// to repeat; no explicit "repeat" instruction terminates loop bodies.
|
||||
loop,
|
||||
/// Merge two error sets into one, `E1 || E2`.
|
||||
merge_error_sets,
|
||||
/// Ambiguously remainder division or modulus. If the computation would possibly have
|
||||
/// a different value depending on whether the operation is remainder division or modulus,
|
||||
/// a compile error is emitted. Otherwise the computation is performed.
|
||||
@ -286,6 +296,8 @@ pub const Inst = struct {
|
||||
.unwrap_err_safe,
|
||||
.unwrap_err_unsafe,
|
||||
.ensure_err_payload_void,
|
||||
.anyframe_type,
|
||||
.bitnot,
|
||||
=> UnOp,
|
||||
|
||||
.add,
|
||||
@ -316,6 +328,8 @@ pub const Inst = struct {
|
||||
.bitcast,
|
||||
.coerce_result_ptr,
|
||||
.xor,
|
||||
.error_union_type,
|
||||
.merge_error_sets,
|
||||
=> BinOp,
|
||||
|
||||
.arg => Arg,
|
||||
@ -347,6 +361,7 @@ pub const Inst = struct {
|
||||
.condbr => CondBr,
|
||||
.ptr_type => PtrType,
|
||||
.enum_literal => EnumLiteral,
|
||||
.error_set => ErrorSet,
|
||||
};
|
||||
}
|
||||
|
||||
@ -438,6 +453,11 @@ pub const Inst = struct {
|
||||
.ptr_type,
|
||||
.ensure_err_payload_void,
|
||||
.enum_literal,
|
||||
.merge_error_sets,
|
||||
.anyframe_type,
|
||||
.error_union_type,
|
||||
.bitnot,
|
||||
.error_set,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@ -908,6 +928,16 @@ pub const Inst = struct {
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const ErrorSet = struct {
|
||||
pub const base_tag = Tag.error_set;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
fields: [][]const u8,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
};
|
||||
|
||||
pub const ErrorMsg = struct {
|
||||
@ -1142,6 +1172,16 @@ const Writer = struct {
|
||||
const name = self.loop_table.get(param).?;
|
||||
return std.zig.renderStringLiteral(name, stream);
|
||||
},
|
||||
[][]const u8 => {
|
||||
try stream.writeByte('[');
|
||||
for (param) |str, i| {
|
||||
if (i != 0) {
|
||||
try stream.writeAll(", ");
|
||||
}
|
||||
try std.zig.renderStringLiteral(str, stream);
|
||||
}
|
||||
try stream.writeByte(']');
|
||||
},
|
||||
else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
|
||||
}
|
||||
}
|
||||
@ -1539,6 +1579,21 @@ const Parser = struct {
|
||||
const name = try self.parseStringLiteral();
|
||||
return self.loop_table.get(name).?;
|
||||
},
|
||||
[][]const u8 => {
|
||||
try requireEatBytes(self, "[");
|
||||
skipSpace(self);
|
||||
if (eatByte(self, ']')) return &[0][]const u8{};
|
||||
|
||||
var strings = std.ArrayList([]const u8).init(&self.arena.allocator);
|
||||
while (true) {
|
||||
skipSpace(self);
|
||||
try strings.append(try self.parseStringLiteral());
|
||||
skipSpace(self);
|
||||
if (!eatByte(self, ',')) break;
|
||||
}
|
||||
try requireEatBytes(self, "]");
|
||||
return strings.toOwnedSlice();
|
||||
},
|
||||
else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
|
||||
}
|
||||
return self.fail("TODO parse parameter {}", .{@typeName(T)});
|
||||
@ -1961,7 +2016,7 @@ const EmitZIR = struct {
|
||||
return self.emitUnnamedDecl(&as_inst.base);
|
||||
},
|
||||
.Type => {
|
||||
const ty = typed_value.val.toType();
|
||||
const ty = try typed_value.val.toType(&self.arena.allocator);
|
||||
return self.emitType(src, ty);
|
||||
},
|
||||
.Fn => {
|
||||
|
||||
@ -97,6 +97,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.array_cat => return analyzeInstArrayCat(mod, scope, old_inst.castTag(.array_cat).?),
|
||||
.array_mul => return analyzeInstArrayMul(mod, scope, old_inst.castTag(.array_mul).?),
|
||||
.bitand => return analyzeInstBitwise(mod, scope, old_inst.castTag(.bitand).?),
|
||||
.bitnot => return analyzeInstBitNot(mod, scope, old_inst.castTag(.bitnot).?),
|
||||
.bitor => return analyzeInstBitwise(mod, scope, old_inst.castTag(.bitor).?),
|
||||
.xor => return analyzeInstBitwise(mod, scope, old_inst.castTag(.xor).?),
|
||||
.shl => return analyzeInstShl(mod, scope, old_inst.castTag(.shl).?),
|
||||
@ -122,6 +123,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.array_type => return analyzeInstArrayType(mod, scope, old_inst.castTag(.array_type).?),
|
||||
.array_type_sentinel => return analyzeInstArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),
|
||||
.enum_literal => return analyzeInstEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?),
|
||||
.merge_error_sets => return analyzeInstMergeErrorSets(mod, scope, old_inst.castTag(.merge_error_sets).?),
|
||||
.error_union_type => return analyzeInstErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?),
|
||||
.anyframe_type => return analyzeInstAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?),
|
||||
.error_set => return analyzeInstErrorSet(mod, scope, old_inst.castTag(.error_set).?),
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +150,7 @@ pub fn analyzeBodyValueAsType(mod: *Module, block_scope: *Scope.Block, body: zir
|
||||
for (block_scope.instructions.items) |inst| {
|
||||
if (inst.castTag(.ret)) |ret| {
|
||||
const val = try mod.resolveConstValue(&block_scope.base, ret.operand);
|
||||
return val.toType();
|
||||
return val.toType(block_scope.base.arena());
|
||||
} else {
|
||||
return mod.fail(&block_scope.base, inst.src, "unable to resolve comptime value", .{});
|
||||
}
|
||||
@ -270,7 +275,7 @@ fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {
|
||||
const wanted_type = Type.initTag(.@"type");
|
||||
const coerced_inst = try mod.coerce(scope, wanted_type, new_inst);
|
||||
const val = try mod.resolveConstValue(scope, coerced_inst);
|
||||
return val.toType();
|
||||
return val.toType(scope.arena());
|
||||
}
|
||||
|
||||
fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 {
|
||||
@ -431,6 +436,7 @@ fn analyzeInstStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerErr
|
||||
// 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.
|
||||
var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
errdefer new_decl_arena.deinit();
|
||||
const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes);
|
||||
|
||||
const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
|
||||
@ -716,6 +722,54 @@ fn analyzeInstArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.Ar
|
||||
return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
|
||||
}
|
||||
|
||||
fn analyzeInstErrorUnionType(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
const error_union = try resolveType(mod, scope, inst.positionals.lhs);
|
||||
const payload = try resolveType(mod, scope, inst.positionals.rhs);
|
||||
|
||||
if (error_union.zigTypeTag() != .ErrorSet) {
|
||||
return mod.fail(scope, inst.base.src, "expected error set type, found {}", .{error_union.elemType()});
|
||||
}
|
||||
|
||||
return mod.constType(scope, inst.base.src, try mod.errorUnionType(scope, error_union, payload));
|
||||
}
|
||||
|
||||
fn analyzeInstAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
const return_type = try resolveType(mod, scope, inst.positionals.operand);
|
||||
|
||||
return mod.constType(scope, inst.base.src, try mod.anyframeType(scope, return_type));
|
||||
}
|
||||
|
||||
fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError!*Inst {
|
||||
// The declarations arena will store the hashmap.
|
||||
var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
|
||||
errdefer new_decl_arena.deinit();
|
||||
|
||||
const payload = try scope.arena().create(Value.Payload.ErrorSet);
|
||||
payload.* = .{
|
||||
.fields = .{},
|
||||
.decl = undefined, // populated below
|
||||
};
|
||||
try payload.fields.ensureCapacity(&new_decl_arena.allocator, inst.positionals.fields.len);
|
||||
|
||||
for (inst.positionals.fields) |field_name| {
|
||||
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});
|
||||
}
|
||||
}
|
||||
// TODO create name in format "error:line:column"
|
||||
const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initPayload(&payload.base),
|
||||
});
|
||||
payload.decl = new_decl;
|
||||
return mod.analyzeDeclRef(scope, inst.base.src, new_decl);
|
||||
}
|
||||
|
||||
fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement merge_error_sets", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
|
||||
const payload = try scope.arena().create(Value.Payload.Bytes);
|
||||
payload.* = .{
|
||||
@ -858,8 +912,72 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
|
||||
);
|
||||
}
|
||||
},
|
||||
else => return mod.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}),
|
||||
.Pointer => {
|
||||
const ptr_child = elem_ty.elemType();
|
||||
switch (ptr_child.zigTypeTag()) {
|
||||
.Array => {
|
||||
if (mem.eql(u8, field_name, "len")) {
|
||||
const len_payload = try scope.arena().create(Value.Payload.Int_u64);
|
||||
len_payload.* = .{ .int = ptr_child.arrayLen() };
|
||||
|
||||
const ref_payload = try scope.arena().create(Value.Payload.RefVal);
|
||||
ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) };
|
||||
|
||||
return mod.constInst(scope, fieldptr.base.src, .{
|
||||
.ty = Type.initTag(.single_const_pointer_to_comptime_int),
|
||||
.val = Value.initPayload(&ref_payload.base),
|
||||
});
|
||||
} else {
|
||||
return mod.fail(
|
||||
scope,
|
||||
fieldptr.positionals.field_name.src,
|
||||
"no member named '{}' in '{}'",
|
||||
.{ field_name, elem_ty },
|
||||
);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
},
|
||||
.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 = try val.toType(scope.arena());
|
||||
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) };
|
||||
|
||||
const result_type = if (child_type.tag() == .anyerror) blk: {
|
||||
const result_payload = try scope.arena().create(Type.Payload.ErrorSetSingle);
|
||||
result_payload.* = .{ .name = entry.key };
|
||||
break :blk Type.initPayload(&result_payload.base);
|
||||
} else child_type;
|
||||
|
||||
return mod.constInst(scope, fieldptr.base.src, .{
|
||||
.ty = try mod.simplePtrType(scope, fieldptr.base.src, result_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});
|
||||
}
|
||||
|
||||
fn analyzeInstIntCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
@ -983,6 +1101,10 @@ fn analyzeInstBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerE
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitwise", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstBitNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitNot", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstArrayCat(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
|
||||
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstArrayCat", .{});
|
||||
}
|
||||
@ -1348,7 +1470,7 @@ fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) Inne
|
||||
|
||||
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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user