stage2: update ZIR for generic functions

ZIR encoding for functions is changed in preparation for generic
function support. As an example:

```zig
const std = @import("std");
const expect = std.testing.expect;

test "example" {
    var x: usize = 0;
    x += checkSize(i32, 1);
    x += checkSize(bool, true);
    try expect(x == 5);
}

fn checkSize(comptime T: type, x: T) usize {
    _ = x;
    return @sizeOf(T);
}
```

Previous ZIR for the `checkSize` function:

```zir
  [165] checkSize line(10) hash(0226f62e189fd0b1c5fca02cf4617562): %55 = block_inline({
    %56 = decl_val("T") token_offset:11:35
    %57 = as_node(@Ref.type_type, %56) node_offset:11:35
    %69 = extended(func([comptime @Ref.type_type, %57], @Ref.usize_type, {
      %58 = arg("T") token_offset:11:23
      %59 = as_node(@Ref.type_type, %58) node_offset:11:35
      %60 = arg("x") token_offset:11:32
      %61 = dbg_stmt(11, 4)
```

ZIR for the `checkSize` function after this commit:

```zir
  [157] checkSize line(10) hash(0226f62e189fd0b1c5fca02cf4617562): %55 = block_inline({
    %56 = param_comptime("T", @Ref.type_type) token_offset:11:23
    %57 = as_node(@Ref.type_type, %56) node_offset:11:35
    %58 = param("x", %57) token_offset:11:32
    %67 = func(@Ref.usize_type, {
      %59 = dbg_stmt(11, 4)
```

Noted differences:
 * Previously the type expression was redundantly repeated.
 * Previously the parameter names were redundantly stored in the ZIR
   extra array.
 * Instead of `arg` ZIR instructions as the first instructions within a
   function body, they are now outside the function body, in the same
   block as the `func` instruction. There are variants:
   - param
   - param_comptime
   - param_anytype
   - param_anytype_comptime
 * The param instructions additionally encode the type.
 * Because of the param instructions, the `func` instruction no longer
   encodes the list of parameter types or the comptime bits.

It's implied that Sema will collect the parameters so that when a `func`
instruction is encountered, they will be implicitly used to construct
the function's type. This is so that we can satisfy all 3 ways of
performing semantic analysis on a function:

 1. runtime: Sema will insert AIR arg instructions for each parameter,
    and insert into the Sema inst_map ZIR param => AIR arg.

 2. comptime/inline: Sema will insert into the inst_map ZIR param =>
    callsite arguments.

 3. generic: Sema will map *only the comptime* ZIR param instructions to
    the AIR instructions for the comptime arguments at the callsite, and
    then re-run Sema for the function's Decl. This will produce a new
    function which is the monomorphized function.

Additionally:

 * AstGen: Update usage of deprecated `ensureCapacity` to
   `ensureUnusedCapacity` or `ensureTotalCapacity`.
 * Introduce `Type.fnInfo` for getting a bunch of data about a function
   type at once, and use it in `analyzeCall`.

This commit starts a branch to implement generic functions in stage2.
Test regressions have not been addressed yet.
This commit is contained in:
Andrew Kelley
2021-08-02 20:35:55 -07:00
parent b465037a65
commit 1472dc3ddb
6 changed files with 431 additions and 378 deletions

View File

@@ -3714,7 +3714,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
decl.analysis = .outdated;
}
fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl {
pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl {
// If we have emit-h then we must allocate a bigger structure to store the emit-h state.
const new_decl: *Decl = if (mod.emit_h != null) blk: {
const parent_struct = try mod.gpa.create(DeclPlusEmitH);