compiler/sem/injectdestructors

  Source   Edit

This module implements the following MIR passes:

  • the 'switch' operation lowering (lowerBranchSwitch)
  • the pass for collapsing sink assignments into copies, moves, and destrutive moves
  • the pass for injecting wasMoved calls for consumed lvalues
  • the pass for eliminating unnecessary destroy operations

The module name is a historical leftover, it doesn't reflect the module's content nor purpose anymore.

Overview

An analysis pass is performed that collects all entities that require destruction into an EntityDict. These are: locals, temporaries, sink parameters, and globals (with some exceptions). If a location has no type-bound =destroy hook (both user-provided and lifted), it is not included.

collapseSink then computes for all lvalue expression appearing as source operands to sink assignments whether it's the last use of the value currently stored in the location identified by the lvalue. All sinks where this is the case are remembered, and their corresponding data-flow operation is turned from a 'use' into a 'consume'.

With all sink assignments either collapsed into copy or move assignments, the next analysis step computes which locations need to be destroyed via a destructor call (see computeDestructors).

As the last step, the assignment rewriting and destructor injection is performed, using the previously gathered data.

Ownership analysis

Reassigning or reading from a location through a handle that is not the owning one is not detected by the analysis. In the following case (assuming no cursor inference):

var a = @[1, 2]
let p = addr a

var b = a
b.add 3
doAssert p[][0] == 1

a = ... # force the earlier move to be destructive

the analysis will detect var b = a to be the last usage of a, subsequently turning the assignment into a move and thus making the assertion fail with an IndexDefect.

Procs

proc injectDestructorCalls(tree: MirTree; g: ModuleGraph; env: var MirEnv;
                           changes: var Changeset) {....raises: [KeyError],
    tags: [].}
Collapses sink assignments into either copy or move assignments, and injects the destroy operations for all entities requiring destruction.   Source   Edit
proc lowerBranchSwitch(tree: MirTree; g: ModuleGraph; idgen: IdGenerator;
                       env: var MirEnv; changes: var Changeset) {.
    ...raises: [Exception, ERecoverableError, KeyError, ValueError],
    tags: [RootEffect, ReadDirEffect].}
Lowers mnkSwitch operations into normal assignments, with a branch destructor injected if the respective record-case requires it (i.e., because it contains fields requiring destruction).   Source   Edit
func shouldInjectDestructorCalls(owner: PSym): bool {....raises: [], tags: [].}
  Source   Edit

Templates

template buildVoidCall(bu: var MirBuilder; env: var MirEnv; p: PSym;
                       body: untyped)
  Source   Edit