aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-08-03 22:34:22 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-08-03 22:34:22 -0700
commit382d201781eb57d9e950ad07ce814adc5a68b329 (patch)
treefd066174fcce78af51e925362c619d1ffd584eef /src/Module.zig
parent609b84611dcde382af5d9fbc2345ede468d31a6f (diff)
downloadzig-382d201781eb57d9e950ad07ce814adc5a68b329.tar.gz
zig-382d201781eb57d9e950ad07ce814adc5a68b329.zip
stage2: basic generic functions are working
The general strategy is that Sema will pre-map comptime arguments into the inst_map, and then re-run the block body that contains the `param` and `func` instructions. This re-runs all the parameter type expressions except with comptime values populated. In Sema, param instructions are now handled specially: they detect whether they are comptime-elided or not. If so, they skip putting a value in the inst_map, since it is already pre-populated. If not, then they append to the `fields` field of `Sema` for use with the `func` instruction. So when the block body is re-run, a new function is generated with all the comptime arguments elided, and the new function type has only runtime parameters in it. TODO: give the generated Decls better names than "foo__anon_x". The new function is then added to the work queue to have its body analyzed and a runtime call AIR instruction to the new function is emitted. When the new function gets semantically analyzed, comptime parameters are pre-mapped to the corresponding `comptime_args` values rather than mapped to an `arg` AIR instruction. `comptime_args` is a new field that `Fn` has which is a `TypedValue` for each parameter. This field is non-null for generic function instantiations only. The values are the comptime arguments. For non-comptime parameters, a sentinel value is used. This is because we need to know the information of which parameters are comptime-known. Additionally: * AstGen: align and section expressions are evaluated in the scope that has comptime parameters in it. There are still some TODO items left; see the BRANCH_TODO file.
Diffstat (limited to 'src/Module.zig')
-rw-r--r--src/Module.zig27
1 files changed, 22 insertions, 5 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 6253e2808d..184ea617b1 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -757,6 +757,10 @@ pub const Union = struct {
pub const Fn = struct {
/// The Decl that corresponds to the function itself.
owner_decl: *Decl,
+ /// If this is not null, this function is a generic function instantiation, and
+ /// there is a `Value` here for each parameter of the function. Non-comptime
+ /// parameters are marked with an `unreachable_value`.
+ comptime_args: ?[*]TypedValue = null,
/// The ZIR instruction that is a function instruction. Use this to find
/// the body. We store this rather than the body directly so that when ZIR
/// is regenerated on update(), we can map this to the new corresponding
@@ -3657,10 +3661,13 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
// Here we are performing "runtime semantic analysis" for a function body, which means
// we must map the parameter ZIR instructions to `arg` AIR instructions.
// AIR requires the `arg` parameters to be the first N instructions.
- const params_len = @intCast(u32, fn_ty.fnParamLen());
- try inner_block.instructions.ensureTotalCapacity(gpa, params_len);
- try sema.air_instructions.ensureUnusedCapacity(gpa, params_len * 2); // * 2 for the `addType`
- try sema.inst_map.ensureUnusedCapacity(gpa, params_len);
+ // This could be a generic function instantiation, however, in which case we need to
+ // map the comptime parameters to constant values and only emit arg AIR instructions
+ // for the runtime ones.
+ const runtime_params_len = @intCast(u32, fn_ty.fnParamLen());
+ try inner_block.instructions.ensureTotalCapacity(gpa, runtime_params_len);
+ try sema.air_instructions.ensureUnusedCapacity(gpa, fn_info.total_params_len * 2); // * 2 for the `addType`
+ try sema.inst_map.ensureUnusedCapacity(gpa, fn_info.total_params_len);
var param_index: usize = 0;
for (fn_info.param_body) |inst| {
@@ -3678,8 +3685,17 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
else => continue,
};
+ if (func.comptime_args) |comptime_args| {
+ const arg_tv = comptime_args[param_index];
+ if (arg_tv.val.tag() != .unreachable_value) {
+ // We have a comptime value for this parameter.
+ const arg = try sema.addConstant(arg_tv.ty, arg_tv.val);
+ sema.inst_map.putAssumeCapacityNoClobber(inst, arg);
+ param_index += 1;
+ continue;
+ }
+ }
const param_type = fn_ty.fnParamType(param_index);
- param_index += 1;
const ty_ref = try sema.addType(param_type);
const arg_index = @intCast(u32, sema.air_instructions.len);
inner_block.instructions.appendAssumeCapacity(arg_index);
@@ -3691,6 +3707,7 @@ pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) SemaError!Air {
} },
});
sema.inst_map.putAssumeCapacityNoClobber(inst, Air.indexToRef(arg_index));
+ param_index += 1;
}
func.state = .in_progress;