aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Module.zig163
-rw-r--r--src/astgen.zig115
-rw-r--r--src/zir.zig60
-rw-r--r--src/zir_sema.zig270
-rw-r--r--test/stage2/aarch64.zig2
-rw-r--r--test/stage2/arm.zig2
-rw-r--r--test/stage2/llvm.zig2
-rw-r--r--test/stage2/test.zig2
8 files changed, 394 insertions, 222 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 747e60f970..7a6dc12967 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -2357,6 +2357,11 @@ pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*De
return self.decl_table.get(name_hash);
}
+pub fn analyzeDeclVal(mod: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
+ const decl_ref = try mod.analyzeDeclRef(scope, src, decl);
+ return mod.analyzeDeref(scope, src, decl_ref, src);
+}
+
pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
const scope_decl = scope.ownerDecl().?;
try self.declareDeclDependency(scope_decl, decl);
@@ -2408,6 +2413,20 @@ fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) Inner
return &inst.base;
}
+pub fn analyzeRef(mod: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst {
+ const ptr_type = try mod.simplePtrType(scope, src, operand.ty, false, .One);
+
+ if (operand.value()) |val| {
+ return mod.constInst(scope, src, .{
+ .ty = ptr_type,
+ .val = try Value.Tag.ref_val.create(scope.arena(), val),
+ });
+ }
+
+ const b = try mod.requireRuntimeBlock(scope, src);
+ return mod.addUnOp(b, src, ptr_type, .ref, operand);
+}
+
pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {
const elem_ty = switch (ptr.ty.zigTypeTag()) {
.Pointer => ptr.ty.elemType(),
@@ -3543,3 +3562,147 @@ pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void {
});
}
}
+
+pub fn namedFieldPtr(
+ mod: *Module,
+ scope: *Scope,
+ src: usize,
+ object_ptr: *Inst,
+ field_name: []const u8,
+ field_name_src: usize,
+) InnerError!*Inst {
+ const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
+ .Pointer => object_ptr.ty.elemType(),
+ else => return mod.fail(scope, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
+ };
+ switch (elem_ty.zigTypeTag()) {
+ .Array => {
+ if (mem.eql(u8, field_name, "len")) {
+ return mod.constInst(scope, src, .{
+ .ty = Type.initTag(.single_const_pointer_to_comptime_int),
+ .val = try Value.Tag.ref_val.create(
+ scope.arena(),
+ try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()),
+ ),
+ });
+ } else {
+ return mod.fail(
+ scope,
+ field_name_src,
+ "no member named '{s}' in '{}'",
+ .{ field_name, elem_ty },
+ );
+ }
+ },
+ .Pointer => {
+ const ptr_child = elem_ty.elemType();
+ switch (ptr_child.zigTypeTag()) {
+ .Array => {
+ if (mem.eql(u8, field_name, "len")) {
+ return mod.constInst(scope, src, .{
+ .ty = Type.initTag(.single_const_pointer_to_comptime_int),
+ .val = try Value.Tag.ref_val.create(
+ scope.arena(),
+ try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()),
+ ),
+ });
+ } else {
+ return mod.fail(
+ scope,
+ field_name_src,
+ "no member named '{s}' in '{}'",
+ .{ field_name, elem_ty },
+ );
+ }
+ },
+ else => {},
+ }
+ },
+ .Type => {
+ _ = try mod.resolveConstValue(scope, object_ptr);
+ const result = try mod.analyzeDeref(scope, 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.castTag(.error_set)) |payload|
+ (payload.data.fields.getEntry(field_name) orelse
+ return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).*
+ else
+ try mod.getErrorValue(field_name);
+
+ const result_type = if (child_type.tag() == .anyerror)
+ try Type.Tag.error_set_single.create(scope.arena(), entry.key)
+ else
+ child_type;
+
+ return mod.constInst(scope, src, .{
+ .ty = try mod.simplePtrType(scope, src, result_type, false, .One),
+ .val = try Value.Tag.ref_val.create(
+ scope.arena(),
+ try Value.Tag.@"error".create(scope.arena(), .{
+ .name = entry.key,
+ .value = entry.value,
+ }),
+ ),
+ });
+ },
+ .Struct => {
+ const container_scope = child_type.getContainerScope();
+ if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
+ // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
+ return mod.analyzeDeclRef(scope, src, decl);
+ }
+
+ if (container_scope.file_scope == mod.root_scope) {
+ return mod.fail(scope, src, "root source file has no member called '{s}'", .{field_name});
+ } else {
+ return mod.fail(scope, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
+ }
+ },
+ else => return mod.fail(scope, src, "type '{}' does not support field access", .{child_type}),
+ }
+ },
+ else => {},
+ }
+ return mod.fail(scope, src, "type '{}' does not support field access", .{elem_ty});
+}
+
+pub fn elemPtr(
+ mod: *Module,
+ scope: *Scope,
+ src: usize,
+ array_ptr: *Inst,
+ elem_index: *Inst,
+) InnerError!*Inst {
+ const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
+ .Pointer => array_ptr.ty.elemType(),
+ else => return mod.fail(scope, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
+ };
+ if (!elem_ty.isIndexable()) {
+ return mod.fail(scope, src, "array access of non-array type '{}'", .{elem_ty});
+ }
+
+ if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
+ // we have to deref the ptr operand to get the actual array pointer
+ const array_ptr_deref = try mod.analyzeDeref(scope, src, array_ptr, array_ptr.src);
+ if (array_ptr_deref.value()) |array_ptr_val| {
+ if (elem_index.value()) |index_val| {
+ // Both array pointer and index are compile-time known.
+ const index_u64 = index_val.toUnsignedInt();
+ // @intCast here because it would have been impossible to construct a value that
+ // required a larger index.
+ const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));
+ const pointee_type = elem_ty.elemType().elemType();
+
+ return mod.constInst(scope, src, .{
+ .ty = try Type.Tag.single_const_pointer.create(scope.arena(), pointee_type),
+ .val = elem_ptr,
+ });
+ }
+ }
+ }
+
+ return mod.fail(scope, src, "TODO implement more analyze elemptr", .{});
+}
diff --git a/src/astgen.zig b/src/astgen.zig
index f24d078b4b..8b4f1cc93c 100644
--- a/src/astgen.zig
+++ b/src/astgen.zig
@@ -278,7 +278,7 @@ 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 errorSetDecl(mod, scope, rl, node.castTag(.ErrorSetDecl).?),
+ .ErrorSetDecl => return rlWrap(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)),
.ErrorType => return rlWrap(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)),
.For => return forExpr(mod, scope, rl, node.castTag(.For).?),
.ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?),
@@ -1107,7 +1107,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
}
}
-fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
+fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
const tree = scope.tree();
const src = tree.token_locs[node.error_token].start;
const decls = node.decls();
@@ -1118,9 +1118,7 @@ fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Erro
fields[i] = try mod.identifierTokenString(scope, tag.name_token);
}
- // analyzing the error set results in a decl ref, so we might need to dereference it
- // TODO remove all callsites to rlWrapPtr
- return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{}));
+ return addZIRInst(mod, scope, src, zir.Inst.ErrorSet, .{ .fields = fields }, .{});
}
fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
@@ -1299,35 +1297,72 @@ fn tokenIdentEql(mod: *Module, scope: *Scope, token1: ast.TokenIndex, token2: as
return mem.eql(u8, ident_name_1, ident_name_2);
}
-pub fn identifierStringInst(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst {
+pub 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.token].start;
-
- const ident_name = try mod.identifierTokenString(scope, node.token);
-
- return addZIRInst(mod, scope, src, zir.Inst.Str, .{ .bytes = ident_name }, .{});
+ const src = tree.token_locs[node.op_token].start;
+ // TODO custom AST node for field access so that we don't have to go through a node cast here
+ const field_name = try mod.identifierTokenString(scope, node.rhs.castTag(.Identifier).?.token);
+ if (rl == .ref) {
+ return addZirInstTag(mod, scope, src, .field_ptr, .{
+ .object = try expr(mod, scope, .ref, node.lhs),
+ .field_name = field_name,
+ });
+ }
+ return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val, .{
+ .object = try expr(mod, scope, .none, node.lhs),
+ .field_name = field_name,
+ }));
}
-fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) InnerError!*zir.Inst {
+fn namedField(
+ mod: *Module,
+ scope: *Scope,
+ rl: ResultLoc,
+ call: *ast.Node.BuiltinCall,
+) InnerError!*zir.Inst {
+ try ensureBuiltinParamCount(mod, scope, call, 2);
+
const tree = scope.tree();
- const src = tree.token_locs[node.op_token].start;
+ const src = tree.token_locs[call.builtin_token].start;
+ const params = call.params();
- const lhs = try expr(mod, scope, .ref, node.lhs);
- const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);
+ const string_type = try addZIRInstConst(mod, scope, src, .{
+ .ty = Type.initTag(.type),
+ .val = Value.initTag(.const_slice_u8_type),
+ });
+ const string_rl: ResultLoc = .{ .ty = string_type };
- // TODO remove all callsites to rlWrapPtr
- return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.FieldPtr, .{ .object_ptr = lhs, .field_name = field_name }, .{}));
+ if (rl == .ref) {
+ return addZirInstTag(mod, scope, src, .field_ptr_named, .{
+ .object = try expr(mod, scope, .ref, params[0]),
+ .field_name = try comptimeExpr(mod, scope, string_rl, params[1]),
+ });
+ }
+ return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .field_val_named, .{
+ .object = try expr(mod, scope, .none, params[0]),
+ .field_name = try comptimeExpr(mod, scope, string_rl, params[1]),
+ }));
}
fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst {
const tree = scope.tree();
const src = tree.token_locs[node.rtoken].start;
+ const usize_type = try addZIRInstConst(mod, scope, src, .{
+ .ty = Type.initTag(.type),
+ .val = Value.initTag(.usize_type),
+ });
+ const index_rl: ResultLoc = .{ .ty = usize_type };
- const array_ptr = try expr(mod, scope, .ref, node.lhs);
- const index = try expr(mod, scope, .none, node.index_expr);
-
- // TODO remove all callsites to rlWrapPtr
- return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.ElemPtr, .{ .array_ptr = array_ptr, .index = index }, .{}));
+ if (rl == .ref) {
+ return addZirInstTag(mod, scope, src, .elem_ptr, .{
+ .array = try expr(mod, scope, .ref, node.lhs),
+ .index = try expr(mod, scope, index_rl, node.index_expr),
+ });
+ }
+ return rlWrap(mod, scope, rl, try addZirInstTag(mod, scope, src, .elem_val, .{
+ .array = try expr(mod, scope, .none, node.lhs),
+ .index = try expr(mod, scope, index_rl, node.index_expr),
+ }));
}
fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.Slice) InnerError!*zir.Inst {
@@ -1819,12 +1854,8 @@ fn forExpr(
break :blk index_ptr;
};
const array_ptr = try expr(mod, &for_scope.base, .ref, for_node.array_expr);
- _ = try addZIRUnOp(mod, &for_scope.base, for_node.array_expr.firstToken(), .ensure_indexable, array_ptr);
const cond_src = tree.token_locs[for_node.array_expr.firstToken()].start;
- const len_ptr = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.FieldPtr, .{
- .object_ptr = array_ptr,
- .field_name = try addZIRInst(mod, &for_scope.base, cond_src, zir.Inst.Str, .{ .bytes = "len" }, .{}),
- }, .{});
+ const len = try addZIRUnOp(mod, &for_scope.base, cond_src, .indexable_ptr_len, array_ptr);
var loop_scope: Scope.GenZIR = .{
.parent = &for_scope.base,
@@ -1845,7 +1876,6 @@ fn forExpr(
// check condition i < array_expr.len
const index = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, index_ptr);
- const len = try addZIRUnOp(mod, &cond_scope.base, cond_src, .deref, len_ptr);
const cond = try addZIRBinOp(mod, &cond_scope.base, cond_src, .cmp_lt, index, len);
const condbr = try addZIRInstSpecial(mod, &cond_scope.base, for_src, zir.Inst.CondBr, .{
@@ -2328,8 +2358,9 @@ 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)) {
- // TODO remove all callsites to rlWrapPtr
- return rlWrapPtr(mod, scope, rl, local_ptr.ptr);
+ if (rl == .ref) return local_ptr.ptr;
+ const loaded = try addZIRUnOp(mod, scope, src, .deref, local_ptr.ptr);
+ return rlWrap(mod, scope, rl, loaded);
}
s = local_ptr.parent;
},
@@ -2747,6 +2778,8 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built
return setEvalBranchQuota(mod, scope, call);
} else if (mem.eql(u8, builtin_name, "@compileLog")) {
return compileLog(mod, scope, call);
+ } else if (mem.eql(u8, builtin_name, "@field")) {
+ return namedField(mod, scope, rl, call);
} else {
return mod.failTok(scope, call.builtin_token, "invalid builtin function: '{s}'", .{builtin_name});
}
@@ -3119,6 +3152,28 @@ fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerEr
return rlWrap(mod, scope, rl, try addZIRUnOp(mod, scope, ptr.src, .deref, ptr));
}
+pub fn addZirInstTag(
+ mod: *Module,
+ scope: *Scope,
+ src: usize,
+ comptime tag: zir.Inst.Tag,
+ positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type,
+) !*zir.Inst {
+ const gen_zir = scope.getGenZIR();
+ try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
+ const inst = try gen_zir.arena.create(tag.Type());
+ inst.* = .{
+ .base = .{
+ .tag = tag,
+ .src = src,
+ },
+ .positionals = positionals,
+ .kw_args = .{},
+ };
+ gen_zir.instructions.appendAssumeCapacity(&inst.base);
+ return &inst.base;
+}
+
pub fn addZIRInstSpecial(
mod: *Module,
scope: *Scope,
diff --git a/src/zir.zig b/src/zir.zig
index be45538288..97c8c94e78 100644
--- a/src/zir.zig
+++ b/src/zir.zig
@@ -47,6 +47,10 @@ pub const Inst = struct {
array_type,
/// Create an array type with sentinel
array_type_sentinel,
+ /// Given a pointer to an indexable object, returns the len property. This is
+ /// used by for loops. This instruction also emits a for-loop specific instruction
+ /// if the indexable object is not indexable.
+ indexable_ptr_len,
/// Function parameter value. These must be first in a function's main block,
/// in respective order with the parameters.
arg,
@@ -142,13 +146,13 @@ pub const Inst = struct {
div,
/// Given a pointer to an array, slice, or pointer, returns a pointer to the element at
/// the provided index.
- elemptr,
+ elem_ptr,
+ /// Given an array, slice, or pointer, returns the element at the provided index.
+ elem_val,
/// Emits a compile error if the operand is not `void`.
ensure_result_used,
/// Emits a compile error if an error is ignored.
ensure_result_non_error,
- /// Emits a compile error if operand cannot be indexed.
- ensure_indexable,
/// Create a `E!T` type.
error_union_type,
/// Create an error set.
@@ -156,8 +160,17 @@ pub const Inst = struct {
/// 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
- /// to the named field.
- fieldptr,
+ /// to the named field. The field name is a []const u8. Used by a.b syntax.
+ field_ptr,
+ /// Given a struct or object that contains virtual fields, returns the named field.
+ /// The field name is a []const u8. Used by a.b syntax.
+ field_val,
+ /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
+ /// to the named field. The field name is a comptime instruction. Used by @field.
+ field_ptr_named,
+ /// Given a struct or object that contains virtual fields, returns the named field.
+ /// The field name is a comptime instruction. Used by @field.
+ field_val_named,
/// Convert a larger float type to any other float type, possibly causing a loss of precision.
floatcast,
/// Declare a function body.
@@ -361,7 +374,6 @@ pub const Inst = struct {
.ptrtoint,
.ensure_result_used,
.ensure_result_non_error,
- .ensure_indexable,
.bitcast_result_ptr,
.ref,
.bitcast_ref,
@@ -391,6 +403,7 @@ pub const Inst = struct {
.bitnot,
.import,
.set_eval_branch_quota,
+ .indexable_ptr_len,
=> UnOp,
.add,
@@ -452,14 +465,15 @@ pub const Inst = struct {
.str => Str,
.int => Int,
.inttype => IntType,
- .fieldptr => FieldPtr,
+ .field_ptr, .field_val => Field,
+ .field_ptr_named, .field_val_named => FieldNamed,
.@"asm" => Asm,
.@"fn" => Fn,
.@"export" => Export,
.param_type => ParamType,
.primitive => Primitive,
.fntype => FnType,
- .elemptr => ElemPtr,
+ .elem_ptr, .elem_val => Elem,
.condbr => CondBr,
.ptr_type => PtrType,
.enum_literal => EnumLiteral,
@@ -490,6 +504,7 @@ pub const Inst = struct {
.array_mul,
.array_type,
.array_type_sentinel,
+ .indexable_ptr_len,
.arg,
.as,
.@"asm",
@@ -523,13 +538,16 @@ pub const Inst = struct {
.declval,
.deref,
.div,
- .elemptr,
+ .elem_ptr,
+ .elem_val,
.ensure_result_used,
.ensure_result_non_error,
- .ensure_indexable,
.@"export",
.floatcast,
- .fieldptr,
+ .field_ptr,
+ .field_val,
+ .field_ptr_named,
+ .field_val_named,
.@"fn",
.fntype,
.int,
@@ -823,12 +841,21 @@ pub const Inst = struct {
kw_args: struct {},
};
- pub const FieldPtr = struct {
- pub const base_tag = Tag.fieldptr;
+ pub const Field = struct {
base: Inst,
positionals: struct {
- object_ptr: *Inst,
+ object: *Inst,
+ field_name: []const u8,
+ },
+ kw_args: struct {},
+ };
+
+ pub const FieldNamed = struct {
+ base: Inst,
+
+ positionals: struct {
+ object: *Inst,
field_name: *Inst,
},
kw_args: struct {},
@@ -1000,12 +1027,11 @@ pub const Inst = struct {
};
};
- pub const ElemPtr = struct {
- pub const base_tag = Tag.elemptr;
+ pub const Elem = struct {
base: Inst,
positionals: struct {
- array_ptr: *Inst,
+ array: *Inst,
index: *Inst,
},
kw_args: struct {},
diff --git a/src/zir_sema.zig b/src/zir_sema.zig
index 82772cac16..b5b256afd3 100644
--- a/src/zir_sema.zig
+++ b/src/zir_sema.zig
@@ -43,8 +43,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.inferred_alloc_mut,
),
.arg => return analyzeInstArg(mod, scope, old_inst.castTag(.arg).?),
- .bitcast_ref => return analyzeInstBitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
- .bitcast_result_ptr => return analyzeInstBitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),
+ .bitcast_ref => return bitCastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
+ .bitcast_result_ptr => return bitCastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),
.block => return analyzeInstBlock(mod, scope, old_inst.castTag(.block).?, false),
.block_comptime => return analyzeInstBlock(mod, scope, old_inst.castTag(.block_comptime).?, true),
.block_flat => return analyzeInstBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false),
@@ -52,7 +52,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.@"break" => return analyzeInstBreak(mod, scope, old_inst.castTag(.@"break").?),
.breakpoint => return analyzeInstBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?),
.breakvoid => return analyzeInstBreakVoid(mod, scope, old_inst.castTag(.breakvoid).?),
- .call => return analyzeInstCall(mod, scope, old_inst.castTag(.call).?),
+ .call => return call(mod, scope, old_inst.castTag(.call).?),
.coerce_result_block_ptr => return analyzeInstCoerceResultBlockPtr(mod, scope, old_inst.castTag(.coerce_result_block_ptr).?),
.coerce_result_ptr => return analyzeInstCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?),
.coerce_to_ptr_elem => return analyzeInstCoerceToPtrElem(mod, scope, old_inst.castTag(.coerce_to_ptr_elem).?),
@@ -60,13 +60,13 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.compilelog => return analyzeInstCompileLog(mod, scope, old_inst.castTag(.compilelog).?),
.@"const" => return analyzeInstConst(mod, scope, old_inst.castTag(.@"const").?),
.dbg_stmt => return analyzeInstDbgStmt(mod, scope, old_inst.castTag(.dbg_stmt).?),
- .declref => return analyzeInstDeclRef(mod, scope, old_inst.castTag(.declref).?),
+ .declref => return declRef(mod, scope, old_inst.castTag(.declref).?),
.declref_str => return analyzeInstDeclRefStr(mod, scope, old_inst.castTag(.declref_str).?),
- .declval => return analyzeInstDeclVal(mod, scope, old_inst.castTag(.declval).?),
+ .declval => return declVal(mod, scope, old_inst.castTag(.declval).?),
.ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?),
.ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),
- .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),
- .ref => return analyzeInstRef(mod, scope, old_inst.castTag(.ref).?),
+ .indexable_ptr_len => return indexablePtrLen(mod, scope, old_inst.castTag(.indexable_ptr_len).?),
+ .ref => return ref(mod, scope, old_inst.castTag(.ref).?),
.resolve_inferred_alloc => return analyzeInstResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?),
.ret_ptr => return analyzeInstRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
.ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),
@@ -88,7 +88,10 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.loop => return analyzeInstLoop(mod, scope, old_inst.castTag(.loop).?),
.param_type => return analyzeInstParamType(mod, scope, old_inst.castTag(.param_type).?),
.ptrtoint => return analyzeInstPtrToInt(mod, scope, old_inst.castTag(.ptrtoint).?),
- .fieldptr => return analyzeInstFieldPtr(mod, scope, old_inst.castTag(.fieldptr).?),
+ .field_ptr => return fieldPtr(mod, scope, old_inst.castTag(.field_ptr).?),
+ .field_val => return fieldVal(mod, scope, old_inst.castTag(.field_val).?),
+ .field_ptr_named => return fieldPtrNamed(mod, scope, old_inst.castTag(.field_ptr_named).?),
+ .field_val_named => return fieldValNamed(mod, scope, old_inst.castTag(.field_val_named).?),
.deref => return analyzeInstDeref(mod, scope, old_inst.castTag(.deref).?),
.as => return analyzeInstAs(mod, scope, old_inst.castTag(.as).?),
.@"asm" => return analyzeInstAsm(mod, scope, old_inst.castTag(.@"asm").?),
@@ -103,7 +106,8 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
.intcast => return analyzeInstIntCast(mod, scope, old_inst.castTag(.intcast).?),
.bitcast => return analyzeInstBitCast(mod, scope, old_inst.castTag(.bitcast).?),
.floatcast => return analyzeInstFloatCast(mod, scope, old_inst.castTag(.floatcast).?),
- .elemptr => return analyzeInstElemPtr(mod, scope, old_inst.castTag(.elemptr).?),
+ .elem_ptr => return elemPtr(mod, scope, old_inst.castTag(.elem_ptr).?),
+ .elem_val => return elemVal(mod, scope, old_inst.castTag(.elem_val).?),
.add => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.add).?),
.addwrap => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.addwrap).?),
.sub => return analyzeInstArithmetic(mod, scope, old_inst.castTag(.sub).?),
@@ -281,16 +285,16 @@ fn analyzeInstCoerceResultBlockPtr(
return mod.fail(scope, inst.base.src, "TODO implement analyzeInstCoerceResultBlockPtr", .{});
}
-fn analyzeInstBitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
+fn bitCastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastRef", .{});
+ return mod.fail(scope, inst.base.src, "TODO implement zir_sema.bitCastRef", .{});
}
-fn analyzeInstBitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
+fn bitCastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- return mod.fail(scope, inst.base.src, "TODO implement analyzeInstBitCastResultPtr", .{});
+ return mod.fail(scope, inst.base.src, "TODO implement zir_sema.bitCastResultPtr", .{});
}
fn analyzeInstCoerceResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
@@ -318,21 +322,12 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr
return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
}
-fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
+fn ref(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- const operand = try resolveInst(mod, scope, inst.positionals.operand);
- const ptr_type = try mod.simplePtrType(scope, inst.base.src, operand.ty, false, .One);
-
- if (operand.value()) |val| {
- return mod.constInst(scope, inst.base.src, .{
- .ty = ptr_type,
- .val = try Value.Tag.ref_val.create(scope.arena(), val),
- });
- }
- const b = try mod.requireRuntimeBlock(scope, inst.base.src);
- return mod.addUnOp(b, inst.base.src, ptr_type, .ref, operand);
+ const operand = try resolveInst(mod, scope, inst.positionals.operand);
+ return mod.analyzeRef(scope, inst.base.src, operand);
}
fn analyzeInstRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
@@ -364,19 +359,34 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
}
}
-fn analyzeInstEnsureIndexable(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
+fn indexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- const operand = try resolveInst(mod, scope, inst.positionals.operand);
- const elem_ty = operand.ty.elemType();
- if (elem_ty.isIndexable()) {
- return mod.constVoid(scope, operand.src);
- } else {
- // TODO error notes
- // error: type '{}' does not support indexing
- // note: for loop operand must be an array, a slice or a tuple
- return mod.fail(scope, operand.src, "for loop operand must be an array, a slice or a tuple", .{});
+
+ const array_ptr = try resolveInst(mod, scope, inst.positionals.operand);
+ const elem_ty = array_ptr.ty.elemType();
+ if (!elem_ty.isIndexable()) {
+ const msg = msg: {
+ const msg = try mod.errMsg(
+ scope,
+ inst.base.src,
+ "type '{}' does not support indexing",
+ .{elem_ty},
+ );
+ errdefer msg.destroy(mod.gpa);
+ try mod.errNote(
+ scope,
+ inst.base.src,
+ msg,
+ "for loop operand must be an array, slice, tuple, or vector",
+ .{},
+ );
+ break :msg msg;
+ };
+ return mod.failWithOwnedErrorMsg(scope, msg);
}
+ const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, array_ptr, "len", inst.base.src);
+ return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);
}
fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
@@ -826,21 +836,19 @@ fn analyzeInstDeclRefStr(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr
return mod.analyzeDeclRefByName(scope, inst.base.src, decl_name);
}
-fn analyzeInstDeclRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
+fn declRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
return mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl);
}
-fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst {
+fn declVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- const decl_ref = try mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl);
- // TODO look into avoiding the call to analyzeDeref here
- return mod.analyzeDeref(scope, inst.base.src, decl_ref, inst.base.src);
+ return mod.analyzeDeclVal(scope, inst.base.src, inst.positionals.decl);
}
-fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
+fn call(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
@@ -1093,7 +1101,7 @@ fn analyzeInstErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) In
.val = Value.initPayload(&payload.base),
});
payload.data.decl = new_decl;
- return mod.analyzeDeclRef(scope, inst.base.src, new_decl);
+ return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
}
fn analyzeInstMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
@@ -1293,108 +1301,46 @@ fn analyzeInstPtrToInt(mod: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) In
return mod.addUnOp(b, ptrtoint.base.src, ty, .ptrtoint, ptr);
}
-fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr) InnerError!*Inst {
+fn fieldVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- const object_ptr = try resolveInst(mod, scope, fieldptr.positionals.object_ptr);
- const field_name = try resolveConstString(mod, scope, fieldptr.positionals.field_name);
- const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
- .Pointer => object_ptr.ty.elemType(),
- else => return mod.fail(scope, fieldptr.positionals.object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
- };
- switch (elem_ty.zigTypeTag()) {
- .Array => {
- if (mem.eql(u8, field_name, "len")) {
- return mod.constInst(scope, fieldptr.base.src, .{
- .ty = Type.initTag(.single_const_pointer_to_comptime_int),
- .val = try Value.Tag.ref_val.create(
- scope.arena(),
- try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()),
- ),
- });
- } else {
- return mod.fail(
- scope,
- fieldptr.positionals.field_name.src,
- "no member named '{s}' in '{}'",
- .{ field_name, elem_ty },
- );
- }
- },
- .Pointer => {
- const ptr_child = elem_ty.elemType();
- switch (ptr_child.zigTypeTag()) {
- .Array => {
- if (mem.eql(u8, field_name, "len")) {
- return mod.constInst(scope, fieldptr.base.src, .{
- .ty = Type.initTag(.single_const_pointer_to_comptime_int),
- .val = try Value.Tag.ref_val.create(
- scope.arena(),
- try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()),
- ),
- });
- } else {
- return mod.fail(
- scope,
- fieldptr.positionals.field_name.src,
- "no member named '{s}' 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.castTag(.error_set)) |payload|
- (payload.data.fields.getEntry(field_name) orelse
- return mod.fail(scope, fieldptr.base.src, "no error named '{s}' in '{}'", .{ field_name, child_type })).*
- else
- try mod.getErrorValue(field_name);
-
- const result_type = if (child_type.tag() == .anyerror)
- try Type.Tag.error_set_single.create(scope.arena(), entry.key)
- else
- child_type;
-
- return mod.constInst(scope, fieldptr.base.src, .{
- .ty = try mod.simplePtrType(scope, fieldptr.base.src, result_type, false, .One),
- .val = try Value.Tag.ref_val.create(
- scope.arena(),
- try Value.Tag.@"error".create(scope.arena(), .{
- .name = entry.key,
- .value = entry.value,
- }),
- ),
- });
- },
- .Struct => {
- const container_scope = child_type.getContainerScope();
- if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
- // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
- return mod.analyzeDeclRef(scope, fieldptr.base.src, decl);
- }
+ const object = try resolveInst(mod, scope, inst.positionals.object);
+ const field_name = inst.positionals.field_name;
+ const object_ptr = try mod.analyzeRef(scope, inst.base.src, object);
+ const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src);
+ return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);
+}
- if (container_scope.file_scope == mod.root_scope) {
- return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{s}'", .{field_name});
- } else {
- return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
- }
- },
- 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 fieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const object_ptr = try resolveInst(mod, scope, inst.positionals.object);
+ const field_name = inst.positionals.field_name;
+ return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src);
+}
+
+fn fieldValNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const object = try resolveInst(mod, scope, inst.positionals.object);
+ const field_name = try resolveConstString(mod, scope, inst.positionals.field_name);
+ const fsrc = inst.positionals.field_name.src;
+ const object_ptr = try mod.analyzeRef(scope, inst.base.src, object);
+ const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc);
+ return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);
+}
+
+fn fieldPtrNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const object_ptr = try resolveInst(mod, scope, inst.positionals.object);
+ const field_name = try resolveConstString(mod, scope, inst.positionals.field_name);
+ const fsrc = inst.positionals.field_name.src;
+ return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc);
}
fn analyzeInstIntCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
@@ -1481,42 +1427,24 @@ fn analyzeInstFloatCast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) Inne
return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten float", .{});
}
-fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) InnerError!*Inst {
+fn elemVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst {
const tracy = trace(@src());
defer tracy.end();
- const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);
- const uncasted_index = try resolveInst(mod, scope, inst.positionals.index);
- const elem_index = try mod.coerce(scope, Type.initTag(.usize), uncasted_index);
- const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
- .Pointer => array_ptr.ty.elemType(),
- else => return mod.fail(scope, inst.positionals.array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
- };
- if (!elem_ty.isIndexable()) {
- return mod.fail(scope, inst.base.src, "array access of non-array type '{}'", .{elem_ty});
- }
-
- if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
- // we have to deref the ptr operand to get the actual array pointer
- const array_ptr_deref = try mod.analyzeDeref(scope, inst.base.src, array_ptr, inst.positionals.array_ptr.src);
- if (array_ptr_deref.value()) |array_ptr_val| {
- if (elem_index.value()) |index_val| {
- // Both array pointer and index are compile-time known.
- const index_u64 = index_val.toUnsignedInt();
- // @intCast here because it would have been impossible to construct a value that
- // required a larger index.
- const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));
- const pointee_type = elem_ty.elemType().elemType();
+ const array = try resolveInst(mod, scope, inst.positionals.array);
+ const array_ptr = try mod.analyzeRef(scope, inst.base.src, array);
+ const elem_index = try resolveInst(mod, scope, inst.positionals.index);
+ const result_ptr = try mod.elemPtr(scope, inst.base.src, array_ptr, elem_index);
+ return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);
+}
- return mod.constInst(scope, inst.base.src, .{
- .ty = try Type.Tag.single_const_pointer.create(scope.arena(), pointee_type),
- .val = elem_ptr,
- });
- }
- }
- }
+fn elemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst {
+ const tracy = trace(@src());
+ defer tracy.end();
- return mod.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{});
+ const array_ptr = try resolveInst(mod, scope, inst.positionals.array);
+ const elem_index = try resolveInst(mod, scope, inst.positionals.index);
+ return mod.elemPtr(scope, inst.base.src, array_ptr, elem_index);
}
fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst {
diff --git a/test/stage2/aarch64.zig b/test/stage2/aarch64.zig
index 6c283f8e9f..3eaf2f51f9 100644
--- a/test/stage2/aarch64.zig
+++ b/test/stage2/aarch64.zig
@@ -80,7 +80,7 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
- var case = ctx.exe("hello world", linux_aarch64);
+ var case = ctx.exe("linux_aarch64 hello world", linux_aarch64);
// Regular old hello world
case.addCompareOutput(
\\export fn _start() noreturn {
diff --git a/test/stage2/arm.zig b/test/stage2/arm.zig
index dcab852784..06e359ccff 100644
--- a/test/stage2/arm.zig
+++ b/test/stage2/arm.zig
@@ -8,7 +8,7 @@ const linux_arm = std.zig.CrossTarget{
pub fn addCases(ctx: *TestContext) !void {
{
- var case = ctx.exe("hello world", linux_arm);
+ var case = ctx.exe("linux_arm hello world", linux_arm);
// Regular old hello world
case.addCompareOutput(
\\export fn _start() noreturn {
diff --git a/test/stage2/llvm.zig b/test/stage2/llvm.zig
index 69622714a7..f52ccecb68 100644
--- a/test/stage2/llvm.zig
+++ b/test/stage2/llvm.zig
@@ -29,7 +29,7 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
- var case = ctx.exeUsingLlvmBackend("hello world", linux_x64);
+ var case = ctx.exeUsingLlvmBackend("llvm hello world", linux_x64);
case.addCompareOutput(
\\extern fn puts(s: [*:0]const u8) c_int;
diff --git a/test/stage2/test.zig b/test/stage2/test.zig
index 845b9b627d..a384e4a8d4 100644
--- a/test/stage2/test.zig
+++ b/test/stage2/test.zig
@@ -231,7 +231,7 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
- var case = ctx.exe("hello world", linux_riscv64);
+ var case = ctx.exe("riscv64 hello world", linux_riscv64);
// Regular old hello world
case.addCompareOutput(
\\export fn _start() noreturn {