mirror of
https://github.com/ziglang/zig.git
synced 2025-01-09 19:50:29 +00:00
astgen: eliminate rlWrapPtr and all its callsites
The following AST avoids unnecessary derefs now: * error set decl * field access * array access * for loops: replace ensure_indexable and deref on the len_ptr with a special purpose ZIR instruction called indexable_ptr_len. Added an error note when for loop operand is the wrong type. I also accidentally implemented `@field`.
This commit is contained in:
parent
7e56028bc7
commit
30a824cb9e
163
src/Module.zig
163
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", .{});
|
||||
}
|
||||
|
119
src/astgen.zig
119
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 {
|
||||
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 }, .{});
|
||||
}
|
||||
|
||||
fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleInfixOp) 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.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,
|
||||
}));
|
||||
}
|
||||
|
||||
const lhs = try expr(mod, scope, .ref, node.lhs);
|
||||
const field_name = try identifierStringInst(mod, scope, node.rhs.castTag(.Identifier).?);
|
||||
fn namedField(
|
||||
mod: *Module,
|
||||
scope: *Scope,
|
||||
rl: ResultLoc,
|
||||
call: *ast.Node.BuiltinCall,
|
||||
) InnerError!*zir.Inst {
|
||||
try ensureBuiltinParamCount(mod, scope, call, 2);
|
||||
|
||||
// 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 }, .{}));
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[call.builtin_token].start;
|
||||
const params = call.params();
|
||||
|
||||
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 };
|
||||
|
||||
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,
|
||||
|
60
src/zir.zig
60
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 {},
|
||||
|
266
src/zir_sema.zig
266
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);
|
||||
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 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);
|
||||
}
|
||||
|
||||
const result_type = if (child_type.tag() == .anyerror)
|
||||
try Type.Tag.error_set_single.create(scope.arena(), entry.key)
|
||||
else
|
||||
child_type;
|
||||
fn fieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
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_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);
|
||||
}
|
||||
|
||||
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 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});
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
fn elemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
return mod.constInst(scope, inst.base.src, .{
|
||||
.ty = try Type.Tag.single_const_pointer.create(scope.arena(), pointee_type),
|
||||
.val = elem_ptr,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user